Netdev List
 help / color / mirror / Atom feed
* Re: bcm43xx: "transmit timed out" and apparent hang with "preemptible periodic work" patches
From: Michael Buesch @ 2006-06-29 15:49 UTC (permalink / raw)
  To: Paul Collins; +Cc: bcm43xx-dev, netdev, linville
In-Reply-To: <87mzbwvv07.fsf@briny.internal.ondioline.org>

On Thursday 29 June 2006 17:31, Paul Collins wrote:
> Michael Buesch <mb@bu3sch.de> writes:
> 
> > On Thursday 29 June 2006 10:24, Paul Collins wrote:
> >> Michael Buesch <mb@bu3sch.de> writes:
> >> 
> >> > On Monday 26 June 2006 14:43, Michael Buesch wrote:
> >> >> Try to get more logs.
> >> >> I suggest to do a netconsole for logging.
> >> >
> >> > Also note that current softmac trees have a patch missing.
> >> > It seems it got lost somewhere after my merge request.
> >> > I already contacted John in private for this, but no reply, yet.
> >> > The patch is attached. Maybe it fixes your issue.
> >> 
> >> On a preempt kernel I can trigger the hang easily,
> >
> > How? I need to reproduce it to get a clue and fix it. :)
> 
> I did it by running the commands I listed in my previous message.
> Here they are again, minus the pesky log messages.
> 
>   ip set link eth1 up
>   ip set link eth1 down
>   iwconfig eth1 essid wlan-ap enc off
>   ip set link eth1 down
>   ip set link eth1 up
>   iwconfig eth1 essid wlan-ap enc off
>   dhclient eth1

Uh, oh. You are doing an up-down-up cycle here...
I might get a clue now. This reminds me of some thought at yesterday
evening. I think that the up-down-up(down-up....) cycle is
broken and works only by accident mostly.
This bug might be hitting you here.
I will do a careful patch and send it out, later.

-- 
Greetings Michael.

^ permalink raw reply

* [2.6 patch] fix the AU1000_FIR dependencies
From: Adrian Bunk @ 2006-06-29 15:41 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Samuel.Ortiz, netdev, linux-kernel, ralf, linux-mips,
	Jean-Luc Leger

This patch fixes the AU1000_FIR dependencies.

Spotted by Jean-Luc Leger.

Signed-off-by: Adrian Bunk <bunk@stusta.de>

---

This patch was already sent on:
- 15 Apr 2006

--- linux-2.6.17-rc1-mm2-full/drivers/net/irda/Kconfig.old	2006-04-15 16:17:36.000000000 +0200
+++ linux-2.6.17-rc1-mm2-full/drivers/net/irda/Kconfig	2006-04-15 16:18:06.000000000 +0200
@@ -350,7 +350,7 @@
 
 config AU1000_FIR
 	tristate "Alchemy Au1000 SIR/FIR"
-	depends on MIPS_AU1000 && IRDA
+	depends on SOC_AU1000 && IRDA
 
 config SMC_IRCC_FIR
 	tristate "SMSC IrCC (EXPERIMENTAL)"

^ permalink raw reply

* Re: bcm43xx: "transmit timed out" and apparent hang with "preemptible periodic work" patches
From: Paul Collins @ 2006-06-29 15:31 UTC (permalink / raw)
  To: Michael Buesch; +Cc: bcm43xx-dev, netdev, linville
In-Reply-To: <200606291707.55172.mb@bu3sch.de>

Michael Buesch <mb@bu3sch.de> writes:

> On Thursday 29 June 2006 10:24, Paul Collins wrote:
>> Michael Buesch <mb@bu3sch.de> writes:
>> 
>> > On Monday 26 June 2006 14:43, Michael Buesch wrote:
>> >> Try to get more logs.
>> >> I suggest to do a netconsole for logging.
>> >
>> > Also note that current softmac trees have a patch missing.
>> > It seems it got lost somewhere after my merge request.
>> > I already contacted John in private for this, but no reply, yet.
>> > The patch is attached. Maybe it fixes your issue.
>> 
>> On a preempt kernel I can trigger the hang easily,
>
> How? I need to reproduce it to get a clue and fix it. :)

I did it by running the commands I listed in my previous message.
Here they are again, minus the pesky log messages.

  ip set link eth1 up
  ip set link eth1 down
  iwconfig eth1 essid wlan-ap enc off
  ip set link eth1 down
  ip set link eth1 up
  iwconfig eth1 essid wlan-ap enc off
  dhclient eth1

I was running a preempt kernel built from Linus's current tree (commit
0a6047eef1c465c38aacfbdab193161b3f0cd144), with your suspend-MAC and
mac_suspended patches applied.  The commit ID encoded in the kernel
version is different because I have some other stuff committed locally:
the bluetooth patch and a couple of snd-aoa fixes.

> I have no idea where it might come from (I don't even know
> what exactly happens).
>
> And please provide a _full_ dmesg log without comments inbetween
> after triggering the hang (with a full Controller Restart cycle).

Here is the entire log, from boot to hang.  There was nothing more
logged on the console beyond what is below.

Jun 29 17:32:21 briny kernel: klogd 1.4.1#18, log source = /proc/kmsg started.
Jun 29 17:32:21 briny kernel: Using PowerMac machine description
Jun 29 17:32:21 briny kernel: Total memory = 1024MB; using 2048kB for hash table (at cfe00000)
Jun 29 17:32:21 briny kernel: Linux version 2.6.17-gfe4aa073-dirty (paul@briny) (gcc version 4.1.2 20060613 (prerelease) (Debian 4.1.1-5)) #6 PREEMPT Thu Jun 29 17:09:48 EST 2006
Jun 29 17:32:21 briny kernel: Found UniNorth memory controller & host bridge @ 0xf8000000 revision: 0xd2
Jun 29 17:32:21 briny kernel: Mapped at 0xfdfc0000
Jun 29 17:32:21 briny kernel: Found a Intrepid mac-io controller, rev: 0, mapped at 0xfdf40000
Jun 29 17:32:21 briny kernel: Processor NAP mode on idle enabled.
Jun 29 17:32:21 briny kernel: PowerMac motherboard: PowerBook G4 15"
Jun 29 17:32:21 briny kernel: via-pmu: Server Mode is disabled
Jun 29 17:32:21 briny kernel: PMU driver v2 initialized for Core99, firmware: 0c
Jun 29 17:32:21 briny kernel: Found UniNorth PCI host bridge at 0xf0000000. Firmware bus number: 0->1
Jun 29 17:32:21 briny kernel: Found UniNorth PCI host bridge at 0xf2000000. Firmware bus number: 0->1
Jun 29 17:32:21 briny kernel: Found UniNorth PCI host bridge at 0xf4000000. Firmware bus number: 0->1
Jun 29 17:32:21 briny kernel: nvram: Checking bank 0...
Jun 29 17:32:21 briny kernel: nvram: gen0=168, gen1=167
Jun 29 17:32:21 briny kernel: nvram: Active bank is: 0
Jun 29 17:32:21 briny kernel: nvram: OF partition at 0x410
Jun 29 17:32:21 briny kernel: nvram: XP partition at 0x1020
Jun 29 17:32:21 briny kernel: nvram: NR partition at 0x1120
Jun 29 17:32:21 briny kernel: Top of RAM: 0x40000000, Total RAM: 0x40000000
Jun 29 17:32:21 briny kernel: Memory hole size: 0MB
Jun 29 17:32:21 briny kernel: On node 0 totalpages: 262144
Jun 29 17:32:21 briny kernel:   DMA zone: 196608 pages, LIFO batch:31
Jun 29 17:32:21 briny kernel:   HighMem zone: 65536 pages, LIFO batch:15
Jun 29 17:32:21 briny kernel: Built 1 zonelists.  Total pages: 262144
Jun 29 17:32:21 briny kernel: Kernel command line: root=/dev/hda3 ro 
Jun 29 17:32:21 briny kernel: mpic: Setting up MPIC " MPIC 1   " version 1.2 at 80040000, max 4 CPUs
Jun 29 17:32:21 briny kernel: mpic: ISU size: 64, shift: 6, mask: 3f
Jun 29 17:32:21 briny kernel: mpic: Initializing for 64 sources
Jun 29 17:32:21 briny kernel: PID hash table entries: 4096 (order: 12, 16384 bytes)
Jun 29 17:32:21 briny kernel: GMT Delta read from XPRAM: 0 minutes, DST: off
Jun 29 17:32:21 briny kernel: time_init: decrementer frequency = 18.432000 MHz
Jun 29 17:32:21 briny kernel: time_init: processor frequency   = 1499.999994 MHz
Jun 29 17:32:21 briny kernel: Console: colour dummy device 80x25
Jun 29 17:32:21 briny kernel: Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
Jun 29 17:32:21 briny kernel: Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
Jun 29 17:32:21 briny kernel: High memory: 262144k
Jun 29 17:32:21 briny kernel: Memory: 1032272k/1048576k available (3556k kernel code, 277880k reserved, 304k data, 392k bss, 164k init)
Jun 29 17:32:21 briny kernel: Calibrating delay loop... 36.73 BogoMIPS (lpj=73472)
Jun 29 17:32:21 briny kernel: Mount-cache hash table entries: 512
Jun 29 17:32:21 briny kernel: device-tree: Duplicate name in /cpus/PowerPC,G4@0, renamed to "l2-cache#1"
Jun 29 17:32:21 briny kernel: NET: Registered protocol family 16
Jun 29 17:32:21 briny kernel: KeyWest i2c @0xf8001003 irq 42 /uni-n@f8000000/i2c@f8001000
Jun 29 17:32:21 briny kernel:  channel 0 bus <multibus>
Jun 29 17:32:21 briny kernel:  channel 1 bus <multibus>
Jun 29 17:32:21 briny kernel: KeyWest i2c @0x80018000 irq 26 /pci@f2000000/mac-io@17/i2c@18000
Jun 29 17:32:21 briny kernel:  channel 0 bus <multibus>
Jun 29 17:32:21 briny kernel: PMU i2c /pci@f2000000/mac-io@17/via-pmu@16000/pmu-i2c
Jun 29 17:32:21 briny kernel:  channel 1 bus <multibus>
Jun 29 17:32:21 briny kernel:  channel 2 bus <multibus>
Jun 29 17:32:21 briny kernel: PCI: Probing PCI hardware
Jun 29 17:32:21 briny kernel: Can't get bus-range for /pci@f2000000/cardbus@13, assuming it starts at 0
Jun 29 17:32:21 briny kernel: PCI: Cannot allocate resource region 0 of device 0001:10:18.0
Jun 29 17:32:21 briny kernel: PCI: Cannot allocate resource region 0 of device 0001:10:19.0
Jun 29 17:32:21 briny kernel: Apple USB OHCI 0001:10:18.0 disabled by firmware
Jun 29 17:32:21 briny kernel: Apple USB OHCI 0001:10:19.0 disabled by firmware
Jun 29 17:32:21 briny kernel: SCSI subsystem initialized
Jun 29 17:32:21 briny kernel: usbcore: registered new driver usbfs
Jun 29 17:32:21 briny kernel: usbcore: registered new driver hub
Jun 29 17:32:21 briny kernel: Bluetooth: Core ver 2.10
Jun 29 17:32:21 briny kernel: NET: Registered protocol family 31
Jun 29 17:32:21 briny kernel: Bluetooth: HCI device and connection manager initialized
Jun 29 17:32:21 briny kernel: Bluetooth: HCI socket layer initialized
Jun 29 17:32:21 briny kernel: NET: Registered protocol family 2
Jun 29 17:32:21 briny kernel: IP route cache hash table entries: 32768 (order: 5, 131072 bytes)
Jun 29 17:32:21 briny kernel: TCP established hash table entries: 131072 (order: 7, 524288 bytes)
Jun 29 17:32:21 briny kernel: TCP bind hash table entries: 65536 (order: 6, 262144 bytes)
Jun 29 17:32:21 briny kernel: TCP: Hash tables configured (established 131072 bind 65536)
Jun 29 17:32:21 briny kernel: TCP reno registered
Jun 29 17:32:21 briny kernel: Registering PowerMac CPU frequency driver
Jun 29 17:32:21 briny kernel: Low: 749 Mhz, High: 1499 Mhz, Boot: 749 Mhz
Jun 29 17:32:21 briny kernel: highmem bounce pool size: 64 pages
Jun 29 17:32:21 briny kernel: fuse init (API version 7.7)
Jun 29 17:32:21 briny kernel: Installing v9fs 9P2000 file system support
Jun 29 17:32:21 briny kernel: Initializing Cryptographic API
Jun 29 17:32:21 briny kernel: io scheduler noop registered
Jun 29 17:32:21 briny kernel: io scheduler anticipatory registered
Jun 29 17:32:21 briny kernel: io scheduler deadline registered
Jun 29 17:32:21 briny kernel: io scheduler cfq registered (default)
Jun 29 17:32:21 briny kernel: PCI: Enabling device 0000:00:10.0 (0006 -> 0007)
Jun 29 17:32:21 briny kernel: radeonfb (0000:00:10.0): Invalid ROM signature 303 should be 0xaa55
Jun 29 17:32:22 briny kernel: radeonfb: Retrieved PLL infos from Open Firmware
Jun 29 17:32:22 briny kernel: radeonfb: Reference=27.00 MHz (RefDiv=12) Memory=203.00 Mhz, System=392.00 MHz
Jun 29 17:32:22 briny kernel: radeonfb: PLL min 12000 max 35000
Jun 29 17:32:22 briny kernel: radeonfb: Monitor 1 type LCD found
Jun 29 17:32:22 briny kernel: radeonfb: EDID probed
Jun 29 17:32:22 briny kernel: radeonfb: Monitor 2 type no found
Jun 29 17:32:22 briny kernel: radeonfb: Using Firmware dividers 0x0002008e from PPLL 0
Jun 29 17:32:22 briny kernel: radeonfb: Dynamic Clock Power Management enabled
Jun 29 17:32:22 briny kernel: Console: switching to colour frame buffer device 106x35
Jun 29 17:32:22 briny kernel: radeonfb: Backlight initialized (radeonbl0)
Jun 29 17:32:22 briny kernel: radeonfb (0000:00:10.0): ATI Radeon NP 
Jun 29 17:32:22 briny kernel: Generic RTC Driver v1.07
Jun 29 17:32:22 briny kernel: Macintosh non-volatile memory driver v1.1
Jun 29 17:32:22 briny kernel: Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing disabled
Jun 29 17:32:22 briny kernel: loop: loaded (max 8 devices)
Jun 29 17:32:22 briny kernel: sungem.c:v0.98 8/24/03 David S. Miller (davem@redhat.com)
Jun 29 17:32:22 briny kernel: PHY ID: 1410cc1, addr: 0
Jun 29 17:32:22 briny kernel: eth0: Sun GEM (PCI) 10/100/1000BaseT Ethernet 00:0d:93:2f:59:34 
Jun 29 17:32:22 briny kernel: eth0: Found Marvell 88E1101 PHY
Jun 29 17:32:22 briny kernel: tun: Universal TUN/TAP device driver, 1.6
Jun 29 17:32:22 briny kernel: tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
Jun 29 17:32:22 briny kernel: MacIO PCI driver attached to Intrepid chipset
Jun 29 17:32:22 briny kernel: input: Macintosh mouse button emulation as /class/input/input0
Jun 29 17:32:22 briny kernel: apm_emu: APM Emulation 0.5 initialized.
Jun 29 17:32:22 briny kernel: adb: starting probe task...
Jun 29 17:32:22 briny kernel: adt746x: version 1 (supported)
Jun 29 17:32:22 briny kernel: adt746x: Thermostat bus: 1, address: 0x2e, limit_adjust: 0, fan_speed: -1
Jun 29 17:32:22 briny kernel: sensor 0: CPU/INTREPID BOTTOMSIDE
Jun 29 17:32:22 briny kernel: sensor 1: CPU BOTTOMSIDE
Jun 29 17:32:22 briny kernel: sensor 2: PWR SUPPLY BOTTOMSIDE
Jun 29 17:32:22 briny kernel: Uniform Multi-Platform E-IDE driver Revision: 7.00alpha2
Jun 29 17:32:22 briny kernel: ide: Assuming 33MHz system bus speed for PIO modes; override with idebus=xx
Jun 29 17:32:22 briny kernel: PCI: Enabling device 0002:24:0d.0 (0000 -> 0002)
Jun 29 17:32:22 briny kernel: adb devices: [2]: 2 c3 [3]: 3 1 [7]: 7 1f
Jun 29 17:32:22 briny kernel: ADB keyboard at 2, handler 1
Jun 29 17:32:22 briny kernel: Detected ADB keyboard, type ANSI.
Jun 29 17:32:22 briny kernel: input: ADB keyboard as /class/input/input1
Jun 29 17:32:22 briny kernel: input: ADB Powerbook buttons as /class/input/input2
Jun 29 17:32:22 briny kernel: ADB mouse at 3, handler set to 4 (trackpad)
Jun 29 17:32:22 briny kernel: input: ADB mouse as /class/input/input3
Jun 29 17:32:22 briny kernel: adb: finished probe task...
Jun 29 17:32:22 briny kernel: ide0: Found Apple UniNorth ATA-6 controller, bus ID 3, irq 39
Jun 29 17:32:22 briny kernel: Probing IDE interface ide0...
Jun 29 17:32:22 briny kernel: hda: HTS541080G9AT00, ATA DISK drive
Jun 29 17:32:22 briny kernel: hda: Enabling Ultra DMA 5
Jun 29 17:32:22 briny kernel: ide0 at 0xf1012000-0xf1012007,0xf1012160 on irq 39
Jun 29 17:32:22 briny kernel: ide1: Found Apple KeyLargo ATA-3 controller, bus ID 0, irq 24
Jun 29 17:32:22 briny kernel: Probing IDE interface ide1...
Jun 29 17:32:22 briny kernel: hdc: MATSHITACD-RW CW-8123, ATAPI CD/DVD-ROM drive
Jun 29 17:32:22 briny kernel: hdc: Enabling MultiWord DMA 2
Jun 29 17:32:22 briny kernel: ide1 at 0xf1006000-0xf1006007,0xf1006160 on irq 24
Jun 29 17:32:22 briny kernel: hda: max request size: 512KiB
Jun 29 17:32:22 briny kernel: hda: 156301488 sectors (80026 MB) w/7539KiB Cache, CHS=16383/255/63, UDMA(100)
Jun 29 17:32:22 briny kernel: hda: cache flushes supported
Jun 29 17:32:22 briny kernel:  hda: [mac] hda1 hda2 hda3 hda4 hda5 hda6 hda7
Jun 29 17:32:22 briny kernel: hdc: ATAPI 24X DVD-ROM CD-R/RW drive, 2048kB Cache, (U)DMA
Jun 29 17:32:22 briny kernel: Uniform CD-ROM driver Revision: 3.20
Jun 29 17:32:22 briny kernel: Initializing USB Mass Storage driver...
Jun 29 17:32:22 briny kernel: usbcore: registered new driver usb-storage
Jun 29 17:32:22 briny kernel: USB Mass Storage support registered.
Jun 29 17:32:22 briny kernel: usbcore: registered new driver hiddev
Jun 29 17:32:22 briny kernel: usbcore: registered new driver usbhid
Jun 29 17:32:22 briny kernel: drivers/usb/input/hid-core.c: v2.6:USB HID core driver
Jun 29 17:32:22 briny kernel: mice: PS/2 mouse device common for all mice
Jun 29 17:32:22 briny kernel: i2c /dev entries driver
Jun 29 17:32:22 briny kernel: PowerMac i2c bus pmu 2 registered
Jun 29 17:32:22 briny kernel: PowerMac i2c bus pmu 1 registered
Jun 29 17:32:22 briny kernel: PowerMac i2c bus mac-io 0 registered
Jun 29 17:32:22 briny kernel: adt746x: ADT7460 initializing
Jun 29 17:32:22 briny kernel: adt746x: Lowering max temperatures from 81, 80, 87 to 70, 50, 70
Jun 29 17:32:22 briny kernel: PowerMac i2c bus uni-n 1 registered
Jun 29 17:32:22 briny kernel: PowerMac i2c bus uni-n 0 registered
Jun 29 17:32:22 briny kernel: device-mapper: ioctl: 4.7.0-ioctl (2006-06-24) initialised: dm-devel@redhat.com
Jun 29 17:32:22 briny kernel: Advanced Linux Sound Architecture Driver Version 1.0.12rc1 (Thu Jun 22 13:55:50 2006 UTC).
Jun 29 17:32:22 briny kernel: ALSA device list:
Jun 29 17:32:22 briny kernel:   No soundcards found.
Jun 29 17:32:22 briny kernel: GRE over IPv4 tunneling driver
Jun 29 17:32:22 briny kernel: TCP bic registered
Jun 29 17:32:22 briny kernel: TCP cubic registered
Jun 29 17:32:22 briny kernel: TCP westwood registered
Jun 29 17:32:22 briny kernel: TCP highspeed registered
Jun 29 17:32:22 briny kernel: TCP hybla registered
Jun 29 17:32:22 briny kernel: TCP htcp registered
Jun 29 17:32:22 briny kernel: TCP vegas registered
Jun 29 17:32:22 briny kernel: TCP veno registered
Jun 29 17:32:22 briny kernel: TCP scalable registered
Jun 29 17:32:22 briny kernel: TCP compound registered
Jun 29 17:32:22 briny kernel: NET: Registered protocol family 1
Jun 29 17:32:22 briny kernel: NET: Registered protocol family 17
Jun 29 17:32:22 briny kernel: Bluetooth: L2CAP ver 2.8
Jun 29 17:32:22 briny kernel: Bluetooth: L2CAP socket layer initialized
Jun 29 17:32:22 briny kernel: Bluetooth: RFCOMM socket layer initialized
Jun 29 17:32:22 briny kernel: Bluetooth: RFCOMM TTY layer initialized
Jun 29 17:32:22 briny kernel: Bluetooth: RFCOMM ver 1.7
Jun 29 17:32:22 briny kernel: Bluetooth: HIDP (Human Interface Emulation) ver 1.1-mh1
Jun 29 17:32:22 briny kernel: input: PMU as /class/input/input4
Jun 29 17:32:22 briny kernel: kjournald starting.  Commit interval 5 seconds
Jun 29 17:32:22 briny kernel: EXT3-fs: mounted filesystem with ordered data mode.
Jun 29 17:32:22 briny kernel: VFS: Mounted root (ext3 filesystem) readonly.
Jun 29 17:32:22 briny kernel: Freeing unused kernel memory: 164k init
Jun 29 17:32:22 briny kernel: ohci_hcd: 2005 April 22 USB 1.1 'Open' Host Controller (OHCI) Driver (PCI)
Jun 29 17:32:22 briny kernel: Apple USB OHCI 0001:10:18.0 disabled by firmware
Jun 29 17:32:22 briny kernel: Apple USB OHCI 0001:10:19.0 disabled by firmware
Jun 29 17:32:22 briny kernel: PCI: Enabling device 0001:10:1a.0 (0000 -> 0002)
Jun 29 17:32:22 briny kernel: ohci_hcd 0001:10:1a.0: OHCI Host Controller
Jun 29 17:32:22 briny kernel: ohci_hcd 0001:10:1a.0: new USB bus registered, assigned bus number 1
Jun 29 17:32:22 briny kernel: ohci_hcd 0001:10:1a.0: irq 29, io mem 0xa0003000
Jun 29 17:32:22 briny kernel: ieee80211_crypt: registered algorithm 'NULL'
Jun 29 17:32:22 briny kernel: ieee80211: 802.11 data/management/control stack, git-1.1.13
Jun 29 17:32:22 briny kernel: ieee80211: Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>
Jun 29 17:32:22 briny kernel: usb usb1: configuration #1 chosen from 1 choice
Jun 29 17:32:22 briny kernel: hub 1-0:1.0: USB hub found
Jun 29 17:32:22 briny kernel: hub 1-0:1.0: 2 ports detected
Jun 29 17:32:22 briny kernel: bcm43xx driver
Jun 29 17:32:22 briny kernel: Linux agpgart interface v0.101 (c) Dave Jones
Jun 29 17:32:22 briny kernel: agpgart: Detected Apple UniNorth 2 chipset
Jun 29 17:32:22 briny kernel: agpgart: configuring for size idx: 4
Jun 29 17:32:22 briny kernel: agpgart: AGP aperture is 16M @ 0x0
Jun 29 17:32:23 briny kernel: PCI: Enabling device 0001:10:1b.2 (0004 -> 0006)
Jun 29 17:32:23 briny kernel: ehci_hcd 0001:10:1b.2: EHCI Host Controller
Jun 29 17:32:23 briny kernel: ehci_hcd 0001:10:1b.2: new USB bus registered, assigned bus number 2
Jun 29 17:32:23 briny kernel: ehci_hcd 0001:10:1b.2: irq 63, io mem 0xa0000000
Jun 29 17:32:23 briny kernel: ehci_hcd 0001:10:1b.2: USB 2.0 started, EHCI 1.00, driver 10 Dec 2004
Jun 29 17:32:23 briny kernel: usb usb2: configuration #1 chosen from 1 choice
Jun 29 17:32:23 briny kernel: hub 2-0:1.0: USB hub found
Jun 29 17:32:23 briny kernel: hub 2-0:1.0: 5 ports detected
Jun 29 17:32:23 briny kernel: Yenta: CardBus bridge found at 0001:10:13.0 [0000:0000]
Jun 29 17:32:23 briny kernel: PCI: Bus 17, cardbus bridge: 0001:10:13.0
Jun 29 17:32:23 briny kernel:   IO window: 00001000-000011ff
Jun 29 17:32:24 briny kernel:   IO window: 00001400-000015ff
Jun 29 17:32:24 briny kernel:   PREFETCH window: 90000000-9fffffff
Jun 29 17:32:25 briny kernel:   MEM window: f3000000-f33fffff
Jun 29 17:32:25 briny kernel: Yenta: Enabling burst memory read transactions
Jun 29 17:32:25 briny kernel: Yenta: Using CSCINT to route CSC interrupts to PCI
Jun 29 17:32:26 briny kernel: Yenta: Routing CardBus interrupts to PCI
Jun 29 17:32:26 briny kernel: usb 1-1: new full speed USB device using ohci_hcd and address 2
Jun 29 17:32:26 briny kernel: Yenta TI: socket 0001:10:13.0, mfunc 0x00001002, devctl 0x60
Jun 29 17:32:26 briny kernel: Yenta: ISA IRQ mask 0x0000, PCI irq 53
Jun 29 17:32:27 briny kernel: Socket status: 30000087
Jun 29 17:32:27 briny kernel: pcmcia: parent PCI bridge I/O window: 0x0 - 0x7fffff
Jun 29 17:32:27 briny kernel: pcmcia: parent PCI bridge Memory window: 0xf3000000 - 0xf3ffffff
Jun 29 17:32:28 briny kernel: pcmcia: parent PCI bridge Memory window: 0x80000000 - 0xafffffff
Jun 29 17:32:28 briny kernel: PCI: Enabling device 0001:10:1b.0 (0000 -> 0002)
Jun 29 17:32:28 briny kernel: ohci_hcd 0001:10:1b.0: OHCI Host Controller
Jun 29 17:32:28 briny kernel: ohci_hcd 0001:10:1b.0: new USB bus registered, assigned bus number 3
Jun 29 17:32:28 briny kernel: ohci_hcd 0001:10:1b.0: irq 63, io mem 0xa0002000
Jun 29 17:32:28 briny kernel: usb 1-1: configuration #1 chosen from 1 choice
Jun 29 17:32:28 briny kernel: usb usb3: configuration #1 chosen from 1 choice
Jun 29 17:32:29 briny kernel: input: HID 05ac:1000 as /class/input/input5
Jun 29 17:32:29 briny kernel: input: USB HID v1.11 Keyboard [HID 05ac:1000] on usb-0001:10:1a.0-1
Jun 29 17:32:29 briny kernel: hub 3-0:1.0: USB hub found
Jun 29 17:32:29 briny kernel: hub 3-0:1.0: 3 ports detected
Jun 29 17:32:29 briny kernel: input: HID 05ac:1000 as /class/input/input6
Jun 29 17:32:29 briny kernel: input: USB HID v1.11 Mouse [HID 05ac:1000] on usb-0001:10:1a.0-1
Jun 29 17:32:29 briny kernel: PCI: Enabling device 0001:10:1b.1 (0000 -> 0002)
Jun 29 17:32:29 briny kernel: ohci_hcd 0001:10:1b.1: OHCI Host Controller
Jun 29 17:32:29 briny kernel: ohci_hcd 0001:10:1b.1: new USB bus registered, assigned bus number 4
Jun 29 17:32:29 briny kernel: ohci_hcd 0001:10:1b.1: irq 63, io mem 0xa0001000
Jun 29 17:32:29 briny kernel: usb usb4: configuration #1 chosen from 1 choice
Jun 29 17:32:30 briny kernel: hub 4-0:1.0: USB hub found
Jun 29 17:32:30 briny kernel: hub 4-0:1.0: 2 ports detected
Jun 29 17:32:30 briny kernel: PCI: Enabling device 0001:10:12.0 (0004 -> 0006)
Jun 29 17:32:30 briny kernel: bcm43xx: Chip ID 0x4306, rev 0x3
Jun 29 17:32:30 briny kernel: bcm43xx: Number of cores: 5
Jun 29 17:32:30 briny kernel: bcm43xx: Core 0: ID 0x800, rev 0x4, vendor 0x4243, enabled
Jun 29 17:32:30 briny kernel: bcm43xx: Core 1: ID 0x812, rev 0x5, vendor 0x4243, disabled
Jun 29 17:32:30 briny kernel: bcm43xx: Core 2: ID 0x80d, rev 0x2, vendor 0x4243, enabled
Jun 29 17:32:30 briny kernel: bcm43xx: Core 3: ID 0x807, rev 0x2, vendor 0x4243, disabled
Jun 29 17:32:30 briny kernel: bcm43xx: Core 4: ID 0x804, rev 0x9, vendor 0x4243, enabled
Jun 29 17:32:30 briny kernel: bcm43xx: PHY connected
Jun 29 17:32:30 briny kernel: bcm43xx: Detected PHY: Version: 2, Type 2, Revision 2
Jun 29 17:32:31 briny kernel: bcm43xx: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)
Jun 29 17:32:31 briny kernel: bcm43xx: Radio turned off
Jun 29 17:32:31 briny kernel: bcm43xx: Radio turned off
Jun 29 17:32:31 briny kernel: snd-aoa-fabric-layout: found bus with layout 51 (using)
Jun 29 17:32:32 briny kernel: snd-aoa-codec-tas: found 'deq' node
Jun 29 17:32:32 briny kernel: snd-aoa-fabric-layout: can use this codec
Jun 29 17:32:32 briny kernel: snd-aoa-codec-tas: created and attached tas instance
Jun 29 17:32:32 briny kernel: EXT3 FS on hda3, internal journal
Jun 29 17:32:33 briny kernel: Bluetooth: HCI USB driver ver 2.9
Jun 29 17:32:33 briny kernel: usbcore: registered new driver hci_usb
Jun 29 17:32:33 briny kernel: usbcore: registered new driver snd-usb-audio
Jun 29 17:32:33 briny kernel: [drm] Initialized drm 1.0.1 20051102
Jun 29 17:32:33 briny kernel: [drm] Initialized radeon 1.25.0 20060524 on minor 0
Jun 29 17:32:33 briny kernel: kjournald starting.  Commit interval 5 seconds
Jun 29 17:32:34 briny kernel: EXT3 FS on hda7, internal journal
Jun 29 17:32:34 briny kernel: EXT3-fs: mounted filesystem with ordered data mode.
Jun 29 17:32:34 briny kernel: kjournald starting.  Commit interval 5 seconds
Jun 29 17:32:34 briny kernel: EXT3 FS on hda4, internal journal
Jun 29 17:32:34 briny kernel: EXT3-fs: mounted filesystem with ordered data mode.
Jun 29 17:32:34 briny kernel: kjournald starting.  Commit interval 5 seconds
Jun 29 17:32:34 briny kernel: EXT3 FS on hda6, internal journal
Jun 29 17:32:35 briny kernel: EXT3-fs: mounted filesystem with ordered data mode.
Jun 29 17:32:35 briny kernel: Adding 1048568k swap on /dev/mapper/swap.  Priority:-1 extents:1 across:1048568k
Jun 29 17:32:35 briny kernel: usb 1-1: usbfs: USBDEVFS_CONTROL failed cmd hid2hci rqt 64 rq 0 len 0 ret -110
Jun 29 17:32:35 briny kernel: usb 1-1: USB disconnect, address 2
Jun 29 17:32:35 briny kernel: usb 1-1: new full speed USB device using ohci_hcd and address 3
Jun 29 17:32:35 briny kernel: usb 1-1: configuration #1 chosen from 1 choice
Jun 29 17:32:48 briny kernel: bcm43xx: PHY connected
Jun 29 17:32:49 briny kernel: bcm43xx: Radio turned on
Jun 29 17:32:49 briny kernel: bcm43xx: Chip initialized
Jun 29 17:32:49 briny kernel: bcm43xx: DMA initialized
Jun 29 17:32:49 briny kernel: bcm43xx: 80211 cores initialized
Jun 29 17:32:49 briny kernel: bcm43xx: Keys cleared
Jun 29 17:32:49 briny kernel: SoftMAC: Open Authentication completed with 00:04:ed:04:1b:96
Jun 29 17:32:55 briny kernel: bcm43xx: Radio turned off
Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0200 (RX) max used slots: 1/64
Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0260 (TX) max used slots: 0/512
Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0240 (TX) max used slots: 0/512
Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0220 (TX) max used slots: 1/512
Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0200 (TX) max used slots: 0/512
Jun 29 17:32:56 briny kernel: bcm43xx: PHY connected
Jun 29 17:32:56 briny kernel: bcm43xx: Radio turned on
Jun 29 17:32:56 briny kernel: bcm43xx: Chip initialized
Jun 29 17:32:56 briny kernel: bcm43xx: DMA initialized
Jun 29 17:32:56 briny kernel: bcm43xx: 80211 cores initialized
Jun 29 17:32:56 briny kernel: bcm43xx: Keys cleared
Jun 29 17:33:14 briny kernel: bcm43xx: set security called, .level = 0, .enabled = 0, .encrypt = 0
Jun 29 17:33:14 briny kernel: SoftMAC: Open Authentication completed with 00:04:ed:04:1b:96
Jun 29 17:33:22 briny kernel: bcm43xx: Radio turned off
Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0200 (RX) max used slots: 1/64
Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0260 (TX) max used slots: 0/512
Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0240 (TX) max used slots: 0/512
Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0220 (TX) max used slots: 1/512
Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0200 (TX) max used slots: 0/512
Jun 29 17:33:27 briny kernel: bcm43xx: PHY connected
Jun 29 17:33:27 briny kernel: bcm43xx: Radio turned on
Jun 29 17:33:27 briny kernel: bcm43xx: Chip initialized
Jun 29 17:33:27 briny kernel: bcm43xx: DMA initialized
Jun 29 17:33:27 briny kernel: bcm43xx: 80211 cores initialized
Jun 29 17:33:27 briny kernel: bcm43xx: Keys cleared
Jun 29 17:33:31 briny kernel: bcm43xx: set security called, .level = 0, .enabled = 0, .encrypt = 0
Jun 29 17:33:31 briny kernel: SoftMAC: Open Authentication completed with 00:04:ed:04:1b:96
Jun 29 17:33:41 briny kernel: NETDEV WATCHDOG: eth1: transmit timed out
Jun 29 17:33:41 briny kernel: bcm43xx: Controller RESET (TX timeout) ...
Jun 29 17:33:41 briny kernel: bcm43xx: Chip ID 0x4306, rev 0x3
Jun 29 17:33:41 briny kernel: bcm43xx: Number of cores: 5
Jun 29 17:33:41 briny kernel: bcm43xx: Core 0: ID 0x800, rev 0x4, vendor 0x4243, enabled
Jun 29 17:33:41 briny kernel: bcm43xx: Core 1: ID 0x812, rev 0x5, vendor 0x4243, disabled
Jun 29 17:33:41 briny kernel: bcm43xx: Core 2: ID 0x80d, rev 0x2, vendor 0x4243, enabled
Jun 29 17:33:41 briny kernel: bcm43xx: Core 3: ID 0x807, rev 0x2, vendor 0x4243, disabled
Jun 29 17:33:41 briny kernel: bcm43xx: Core 4: ID 0x804, rev 0x9, vendor 0x4243, enabled
Jun 29 17:33:41 briny kernel: bcm43xx: PHY connected
Jun 29 17:33:41 briny kernel: bcm43xx: Detected PHY: Version: 2, Type 2, Revision 2
Jun 29 17:33:41 briny kernel: bcm43xx: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)
Jun 29 17:33:41 briny kernel: bcm43xx: Radio turned off
Jun 29 17:33:41 briny kernel: bcm43xx: Radio turned off
Jun 29 17:33:41 briny kernel: bcm43xx: Controller restarted

-- 
Paul Collins
Melbourne, Australia

Dag vijandelijk luchtschip de huismeester is dood

^ permalink raw reply

* [PATCH 3/3] [TIPC] Initial activation message now includes TIPC version number
From: Per Liden @ 2006-06-29 15:36 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Allan Stephens
In-Reply-To: <Pine.LNX.4.64.0606291719220.1695@ulinpc219.uab.ericsson.se>

From: Allan Stephens <allan.stephens@windriver.com>

Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: Per Liden <per.liden@ericsson.com>
---
 net/tipc/core.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/net/tipc/core.c b/net/tipc/core.c
index 5003acb..0539a83 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -191,7 +191,8 @@ static int __init tipc_init(void)
 	int res;
 
 	tipc_log_reinit(CONFIG_TIPC_LOG);
-	info("Activated (compiled " __DATE__ " " __TIME__ ")\n");
+	info("Activated (version " TIPC_MOD_VER 
+	     " compiled " __DATE__ " " __TIME__ ")\n");
 
 	tipc_own_addr = 0;
 	tipc_remote_management = 1;
-- 
1.4.0


^ permalink raw reply related

* [PATCH 2/3] [TIPC] Improve response to requests for node/link information
From: Per Liden @ 2006-06-29 15:36 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Allan Stephens
In-Reply-To: <Pine.LNX.4.64.0606291719220.1695@ulinpc219.uab.ericsson.se>

From: Allan Stephens <allan.stephens@windriver.com>

Now allocates reply space for "get links" request based on number of actual
links, not number of potential links.  Also, limits reply to "get links" and
"get nodes" requests to 32KB to match capabilities of tipc-config utility
that issued request.

Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: Per Liden <per.liden@ericsson.com>
---
 net/tipc/node.c |   26 +++++++++++++++++---------
 net/tipc/zone.h |    4 ++--
 2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/net/tipc/node.c b/net/tipc/node.c
index ce9678e..bf24168 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -2,7 +2,7 @@
  * net/tipc/node.c: TIPC node management routines
  * 
  * Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -592,6 +592,7 @@ struct sk_buff *tipc_node_get_nodes(cons
 	struct sk_buff *buf;
 	struct node *n_ptr;
         struct tipc_node_info node_info;
+	u32 payload_size;
 
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
@@ -608,8 +609,11 @@ struct sk_buff *tipc_node_get_nodes(cons
 	/* For now, get space for all other nodes 
 	   (will need to modify this when slave nodes are supported */
 
-	buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(node_info)) *
-				   (tipc_max_nodes - 1));
+	payload_size = TLV_SPACE(sizeof(node_info)) * (tipc_max_nodes - 1);
+	if (payload_size > 32768u)
+		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+						   " (too many nodes)");
+	buf = tipc_cfg_reply_alloc(payload_size);
 	if (!buf)
 		return NULL;
 
@@ -633,6 +637,7 @@ struct sk_buff *tipc_node_get_links(cons
 	struct sk_buff *buf;
 	struct node *n_ptr;
         struct tipc_link_info link_info;
+	u32 payload_size;
 
 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
@@ -645,12 +650,15 @@ struct sk_buff *tipc_node_get_links(cons
 
         if (!tipc_nodes)
                 return tipc_cfg_reply_none();
-
-	/* For now, get space for 2 links to all other nodes + bcast link 
-	   (will need to modify this when slave nodes are supported */
-
-	buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(link_info)) *
-				   (2 * (tipc_max_nodes - 1) + 1));
+	
+	/* Get space for all unicast links + multicast link */
+
+	payload_size = TLV_SPACE(sizeof(link_info)) *
+		(tipc_net.zones[tipc_zone(tipc_own_addr)]->links + 1);
+	if (payload_size > 32768u)
+		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+						   " (too many links)");
+	buf = tipc_cfg_reply_alloc(payload_size);
 	if (!buf)
 		return NULL;
 
diff --git a/net/tipc/zone.h b/net/tipc/zone.h
index 267999c..5ab3d08 100644
--- a/net/tipc/zone.h
+++ b/net/tipc/zone.h
@@ -2,7 +2,7 @@
  * net/tipc/zone.h: Include file for TIPC zone management routines
  * 
  * Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@ #include "net.h"
  * struct _zone - TIPC zone structure
  * @addr: network address of zone
  * @clusters: array of pointers to all clusters within zone
- * @links: (used for inter-zone communication)
+ * @links: number of (unicast) links to zone
  */
  
 struct _zone {
-- 
1.4.0


^ permalink raw reply related

* [PATCH 1/3] [TIPC] Fixed skb_under_panic caused by tipc_link_bundle_buf
From: Per Liden @ 2006-06-29 15:36 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Allan Stephens
In-Reply-To: <Pine.LNX.4.64.0606291719220.1695@ulinpc219.uab.ericsson.se>

From: Allan Stephens <allan.stephens@windriver.com>

Now determines tailroom of bundle buffer by directly inspection of buffer.
Previously, buffer was assumed to have a max capacity equal to the link MTU,
but the addition of link MTU negotiation means that the link MTU can increase
after the bundle buffer is allocated.

Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: Per Liden <per.liden@ericsson.com>
---
 net/tipc/core.h |    5 ++++-
 net/tipc/link.c |   13 ++++++++-----
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/net/tipc/core.h b/net/tipc/core.h
index 86f54f3..762aac2 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -297,7 +297,10 @@ static inline struct tipc_msg *buf_msg(s
  * buf_acquire - creates a TIPC message buffer
  * @size: message size (including TIPC header)
  *
- * Returns a new buffer.  Space is reserved for a data link header.
+ * Returns a new buffer with data pointers set to the specified size.
+ * 
+ * NOTE: Headroom is reserved to allow prepending of a data link header.
+ *       There may also be unrequested tailroom present at the buffer's end.
  */
 
 static inline struct sk_buff *buf_acquire(u32 size)
diff --git a/net/tipc/link.c b/net/tipc/link.c
index d646580..c10e18a 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -2,7 +2,7 @@
  * net/tipc/link.c: TIPC link code
  * 
  * Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2004-2006, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -988,17 +988,20 @@ static int link_bundle_buf(struct link *
 	struct tipc_msg *bundler_msg = buf_msg(bundler);
 	struct tipc_msg *msg = buf_msg(buf);
 	u32 size = msg_size(msg);
-	u32 to_pos = align(msg_size(bundler_msg));
-	u32 rest = link_max_pkt(l_ptr) - to_pos;
+	u32 bundle_size = msg_size(bundler_msg);
+	u32 to_pos = align(bundle_size);
+	u32 pad = to_pos - bundle_size;
 
 	if (msg_user(bundler_msg) != MSG_BUNDLER)
 		return 0;
 	if (msg_type(bundler_msg) != OPEN_MSG)
 		return 0;
-	if (rest < align(size))
+	if (skb_tailroom(bundler) < (pad + size))
+		return 0;
+	if (link_max_pkt(l_ptr) < (to_pos + size))
 		return 0;
 
-	skb_put(bundler, (to_pos - msg_size(bundler_msg)) + size);
+	skb_put(bundler, pad + size);
 	memcpy(bundler->data + to_pos, buf->data, size);
 	msg_set_size(bundler_msg, to_pos + size);
 	msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
-- 
1.4.0


^ permalink raw reply related

* [PATCH 0/3] TIPC updates (resend)
From: Per Liden @ 2006-06-29 15:34 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, per.liden, Allan Stephens

This is a resend of this patch set. A problem was found with the direct 
inspection of bundle buffer tailroom. It did not account for the 
possiblity of unrequested tailroom added by skb_alloc(), thereby allowing 
a bundle to be created that exceeds the current link MTU. An additional 
check now ensures that bundling works correctly no matter if the bundle 
buffer is smaller, larger, or equal to the link MTU.

Please pull from:

 git://tipc.cslab.ericsson.net/pub/git/tipc.git

Summary:

 net/tipc/core.c |    3 ++-
 net/tipc/core.h |    5 ++++-
 net/tipc/link.c |   13 ++++++++-----
 net/tipc/node.c |   26 +++++++++++++++++---------
 net/tipc/zone.h |    4 ++--
 5 files changed, 33 insertions(+), 18 deletions(-)

Allan Stephens:
      [TIPC] Fixed skb_under_panic caused by tipc_link_bundle_buf
      [TIPC] Improve response to requests for node/link information
      [TIPC] Initial activation message now includes TIPC version number

/Per

^ permalink raw reply

* Re: bcm43xx: "transmit timed out" and apparent hang with "preemptible periodic work" patches
From: Michael Buesch @ 2006-06-29 15:31 UTC (permalink / raw)
  To: Larry Finger; +Cc: Paul Collins, bcm43xx-dev, netdev, linville
In-Reply-To: <44A3F052.7030905@lwfinger.net>

On Thursday 29 June 2006 17:22, Larry Finger wrote:
> Michael Buesch wrote:
> > On Thursday 29 June 2006 10:24, Paul Collins wrote:
> >> Michael Buesch <mb@bu3sch.de> writes:
> >>
> >>> On Monday 26 June 2006 14:43, Michael Buesch wrote:
> >>>> Try to get more logs.
> >>>> I suggest to do a netconsole for logging.
> >>> Also note that current softmac trees have a patch missing.
> >>> It seems it got lost somewhere after my merge request.
> >>> I already contacted John in private for this, but no reply, yet.
> >>> The patch is attached. Maybe it fixes your issue.
> >> On a preempt kernel I can trigger the hang easily,
> > 
> > How? I need to reproduce it to get a clue and fix it. :)
> > I have no idea where it might come from (I don't even know
> > what exactly happens).
> > 
> > And please provide a _full_ dmesg log without comments inbetween
> > after triggering the hang (with a full Controller Restart cycle).
> > 
> 
> I am having what I think is a similar problem, although my system does not hang. I cannot send dmesg 
> output as the buffer is quickly filled with the channel assertion messages you see below, but here 
> is the relevant section of /var/log/messages.
> 
> Jun 29 01:22:08 larrylap kernel: NETDEV WATCHDOG: wlan0: transmit timed out
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Controller RESET (TX timeout) ...
> Jun 29 01:22:08 larrylap kernel: ACPI: PCI interrupt for device 0000:02:00.0 disabled
> Jun 29 01:22:08 larrylap kernel: PCI: Enabling device 0000:02:00.0 (0000 -> 0002)
> Jun 29 01:22:08 larrylap kernel: ACPI: PCI Interrupt 0000:02:00.0[A] -> Link [LNKA] -> GSI 11 
> (level, low) -> IRQ 11
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Chip ID 0x4306, rev 0x2
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Number of cores: 6
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 0: ID 0x800, rev 0x2, vendor 0x4243, enabled
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 1: ID 0x812, rev 0x4, vendor 0x4243, enabled
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 2: ID 0x80d, rev 0x1, vendor 0x4243, enabled
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 3: ID 0x807, rev 0x1, vendor 0x4243, disabled
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 4: ID 0x804, rev 0x7, vendor 0x4243, enabled
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 5: ID 0x812, rev 0x4, vendor 0x4243, disabled
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Ignoring additional 802.11 core.
> Jun 29 01:22:08 larrylap kernel: bcm43xx: PHY connected
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Detected PHY: Version: 1, Type 2, Revision 1
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Radio turned off
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Radio turned off
> Jun 29 01:22:08 larrylap kernel: bcm43xx: Controller restarted
> Jun 29 01:23:08 larrylap kernel: bcm43xx: ASSERTION FAILED (channel >= 1 && channel <= 14) at: 
> drivers/net/wireless/bcm43xx/bcm43xx_radio.c:79:channel2freq_bg()

WTF is that???
How is that possible to happen?
Are you sure you have an unmodified tree?

> Jun 29 01:24:08 larrylap kernel: bcm43xx: ASSERTION FAILED (channel >= 1 && channel <= 14) at: 
> drivers/net/wireless/bcm43xx/bcm43xx_radio.c:79:channel2freq_bg()
> Jun 29 01:25:08 larrylap kernel: bcm43xx: ASSERTION FAILED (channel >= 1 && channel <= 14) at: 
> drivers/net/wireless/bcm43xx/bcm43xx_radio.c:79:channel2freq_bg()
> 
> These continue until the interface is brought down. My kernel is 2.6.17-g569df601-dirty from 
> Linville's tree, is preemptible and all recent patches are installed.
> 
> Larry
> 
> 

-- 
Greetings Michael.

^ permalink raw reply

* Re: [PATCH] improved statistics for bcm43xx-softmac
From: Larry Finger @ 2006-06-29 15:31 UTC (permalink / raw)
  To: Michael Buesch; +Cc: John Linville, netdev
In-Reply-To: <200606291712.21973.mb@bu3sch.de>

Michael Buesch wrote:
> On Thursday 29 June 2006 06:08, Larry Finger wrote:
>> 	/* fill in the real statistics when iface associated */
>> -	wstats->qual.qual = 100;     // TODO: get the real signal quality
>> -	wstats->qual.level = 3 - bcm->stats.link_quality;
>> +	list_for_each_entry(network, &mac->ieee->network_list, list) {
>> +		if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
>> +			if (!tmp_level)		/* get initial value */
>> +				tmp_level = network->stats.rssi;
>> +			else			/* smooth results */
>> +				tmp_level = (7 * tmp_level + network->stats.rssi)/8;
>> +			break;
>> +		}
>> +	}
> 
> You need to lock the ieee80211 lock here. Otherwise it might race and crash,
> if some workqueue modifies the list inbetween.

Thanks for the comment. Is there an easier way to get to network->stats?

Larry

^ permalink raw reply

* Re: bcm43xx: "transmit timed out" and apparent hang with "preemptible periodic work" patches
From: Larry Finger @ 2006-06-29 15:22 UTC (permalink / raw)
  To: Michael Buesch; +Cc: Paul Collins, bcm43xx-dev, netdev, linville
In-Reply-To: <200606291707.55172.mb@bu3sch.de>

Michael Buesch wrote:
> On Thursday 29 June 2006 10:24, Paul Collins wrote:
>> Michael Buesch <mb@bu3sch.de> writes:
>>
>>> On Monday 26 June 2006 14:43, Michael Buesch wrote:
>>>> Try to get more logs.
>>>> I suggest to do a netconsole for logging.
>>> Also note that current softmac trees have a patch missing.
>>> It seems it got lost somewhere after my merge request.
>>> I already contacted John in private for this, but no reply, yet.
>>> The patch is attached. Maybe it fixes your issue.
>> On a preempt kernel I can trigger the hang easily,
> 
> How? I need to reproduce it to get a clue and fix it. :)
> I have no idea where it might come from (I don't even know
> what exactly happens).
> 
> And please provide a _full_ dmesg log without comments inbetween
> after triggering the hang (with a full Controller Restart cycle).
> 

I am having what I think is a similar problem, although my system does not hang. I cannot send dmesg 
output as the buffer is quickly filled with the channel assertion messages you see below, but here 
is the relevant section of /var/log/messages.

Jun 29 01:22:08 larrylap kernel: NETDEV WATCHDOG: wlan0: transmit timed out
Jun 29 01:22:08 larrylap kernel: bcm43xx: Controller RESET (TX timeout) ...
Jun 29 01:22:08 larrylap kernel: ACPI: PCI interrupt for device 0000:02:00.0 disabled
Jun 29 01:22:08 larrylap kernel: PCI: Enabling device 0000:02:00.0 (0000 -> 0002)
Jun 29 01:22:08 larrylap kernel: ACPI: PCI Interrupt 0000:02:00.0[A] -> Link [LNKA] -> GSI 11 
(level, low) -> IRQ 11
Jun 29 01:22:08 larrylap kernel: bcm43xx: Chip ID 0x4306, rev 0x2
Jun 29 01:22:08 larrylap kernel: bcm43xx: Number of cores: 6
Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 0: ID 0x800, rev 0x2, vendor 0x4243, enabled
Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 1: ID 0x812, rev 0x4, vendor 0x4243, enabled
Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 2: ID 0x80d, rev 0x1, vendor 0x4243, enabled
Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 3: ID 0x807, rev 0x1, vendor 0x4243, disabled
Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 4: ID 0x804, rev 0x7, vendor 0x4243, enabled
Jun 29 01:22:08 larrylap kernel: bcm43xx: Core 5: ID 0x812, rev 0x4, vendor 0x4243, disabled
Jun 29 01:22:08 larrylap kernel: bcm43xx: Ignoring additional 802.11 core.
Jun 29 01:22:08 larrylap kernel: bcm43xx: PHY connected
Jun 29 01:22:08 larrylap kernel: bcm43xx: Detected PHY: Version: 1, Type 2, Revision 1
Jun 29 01:22:08 larrylap kernel: bcm43xx: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)
Jun 29 01:22:08 larrylap kernel: bcm43xx: Radio turned off
Jun 29 01:22:08 larrylap kernel: bcm43xx: Radio turned off
Jun 29 01:22:08 larrylap kernel: bcm43xx: Controller restarted
Jun 29 01:23:08 larrylap kernel: bcm43xx: ASSERTION FAILED (channel >= 1 && channel <= 14) at: 
drivers/net/wireless/bcm43xx/bcm43xx_radio.c:79:channel2freq_bg()
Jun 29 01:24:08 larrylap kernel: bcm43xx: ASSERTION FAILED (channel >= 1 && channel <= 14) at: 
drivers/net/wireless/bcm43xx/bcm43xx_radio.c:79:channel2freq_bg()
Jun 29 01:25:08 larrylap kernel: bcm43xx: ASSERTION FAILED (channel >= 1 && channel <= 14) at: 
drivers/net/wireless/bcm43xx/bcm43xx_radio.c:79:channel2freq_bg()

These continue until the interface is brought down. My kernel is 2.6.17-g569df601-dirty from 
Linville's tree, is preemptible and all recent patches are installed.

Larry


^ permalink raw reply

* Re: [PATCH 1/3] [TIPC] Fixed skb_under_panic caused by tipc_link_bundle_buf
From: Per Liden @ 2006-06-29 15:17 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Allan Stephens
In-Reply-To: <11514964722073-git-send-email-per.liden@ericsson.com>

A problem was found with this patch. The direct inspection of bundle 
buffer tailroom did not account for the possiblity of unrequested tailroom 
added by skb_alloc(), thereby allowing a bundle to be created that exceeds 
the current link MTU.

I'll resend this patch set with this issue resolved.

/Per

On Wed, 28 Jun 2006, Per Liden wrote:

> From: Allan Stephens <allan.stephens@windriver.com>
> 
> Now determines tailroom of bundle buffer by directly inspection of buffer.
> Previously, buffer was assumed to have a max capacity equal to the link MTU,
> but the addition of link MTU negotiation means that the link MTU can increase
> after the bundle buffer is allocated.
> 
> Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
> Signed-off-by: Per Liden <per.liden@ericsson.com>
> ---
>  net/tipc/link.c |   11 ++++++-----
>  1 files changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/net/tipc/link.c b/net/tipc/link.c
> index d646580..c6831c7 100644
> --- a/net/tipc/link.c
> +++ b/net/tipc/link.c
> @@ -2,7 +2,7 @@
>   * net/tipc/link.c: TIPC link code
>   * 
>   * Copyright (c) 1996-2006, Ericsson AB
> - * Copyright (c) 2004-2005, Wind River Systems
> + * Copyright (c) 2004-2006, Wind River Systems
>   * All rights reserved.
>   *
>   * Redistribution and use in source and binary forms, with or without
> @@ -988,17 +988,18 @@ static int link_bundle_buf(struct link *
>  	struct tipc_msg *bundler_msg = buf_msg(bundler);
>  	struct tipc_msg *msg = buf_msg(buf);
>  	u32 size = msg_size(msg);
> -	u32 to_pos = align(msg_size(bundler_msg));
> -	u32 rest = link_max_pkt(l_ptr) - to_pos;
> +	u32 bundle_size = msg_size(bundler_msg);
> +	u32 to_pos = align(bundle_size);
> +	u32 pad = to_pos - bundle_size;
>  
>  	if (msg_user(bundler_msg) != MSG_BUNDLER)
>  		return 0;
>  	if (msg_type(bundler_msg) != OPEN_MSG)
>  		return 0;
> -	if (rest < align(size))
> +	if (skb_tailroom(bundler) < (pad + size))
>  		return 0;
>  
> -	skb_put(bundler, (to_pos - msg_size(bundler_msg)) + size);
> +	skb_put(bundler, pad + size);
>  	memcpy(bundler->data + to_pos, buf->data, size);
>  	msg_set_size(bundler_msg, to_pos + size);
>  	msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
> -- 
> 1.4.0
> 
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" 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: [PATCH] improved statistics for bcm43xx-softmac
From: Michael Buesch @ 2006-06-29 15:12 UTC (permalink / raw)
  To: Larry Finger; +Cc: John Linville, netdev
In-Reply-To: <44A3524C.40704@lwfinger.net>

On Thursday 29 June 2006 06:08, Larry Finger wrote:
> This patch improves the statistics returned from bcm43xx_get_wireless_stats. The signal level comes
> from smoothing the rssi value returned by the firmware. The quality value is a hack derived from the
> smoothed rssi value and an assumed rssi_max of -25. If anyone has a better value, please let me
> know. The noise value is still the one calculated from the clean-room formula. On my system, this is
> roughly -65 dBm, which seems too high. I would appreciate getting any ideas on what other 
> interface/driver combinations get for the noise value.
> 
> Signed-Off-By: Larry Finger <Larry.Finger@lwfinger.net>
> 
> ==========================================================
> 
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> index af97755..c80fdcd 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
> @@ -1581,17 +1581,8 @@ static void handle_irq_noise(struct bcm4
> 		else
> 			average -= 48;
> 
> -/* FIXME: This is wrong, but people want fancy stats. well... */
> -bcm->stats.noise = average;
> -		if (average > -65)
> -			bcm->stats.link_quality = 0;
> -		else if (average > -75)
> -			bcm->stats.link_quality = 1;
> -		else if (average > -85)
> -			bcm->stats.link_quality = 2;
> -		else
> -			bcm->stats.link_quality = 3;
> -//		dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
> +/* FIXME: This matches the formula from the clean-room, but yields a value that is probably too
> large. */
> +		bcm->stats.noise = average;
>   drop_calculation:
> 		bcm->noisecalc.calculation_running = 0;
> 		return;
> diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
> index 5c36e29..8224da1 100644
> --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
> +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
> @@ -47,6 +47,8 @@ #include "bcm43xx_phy.h"
>   #define BCM43xx_WX_VERSION	18
> 
>   #define MAX_WX_STRING		80
> +/* FIXME: the next line is a guess as to what the maximum value of rssi might be */
> +#define RSSI_MAX		-25
> 
> 
>   static int bcm43xx_wx_get_name(struct net_device *net_dev,
> @@ -227,15 +229,15 @@ static int bcm43xx_wx_get_rangeparams(st
> 
> 	range->max_qual.qual = 100;
> 	/* TODO: Real max RSSI */
> -	range->max_qual.level = 3;
> -	range->max_qual.noise = 100;
> -	range->max_qual.updated = 7;
> -
> -	range->avg_qual.qual = 70;
> -	range->avg_qual.level = 2;
> -	range->avg_qual.noise = 40;
> -	range->avg_qual.updated = 7;
> -
> +	range->max_qual.level = -100;
> +	range->max_qual.noise = -100;
> +	range->max_qual.updated = IW_QUAL_ALL_UPDATED;
> +
> +	range->avg_qual.qual = 50;
> +	range->avg_qual.level = -40;
> +	range->avg_qual.noise = -65;
> +	range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
> +
> 	range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
> 	range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
> 	range->min_frag = MIN_FRAG_THRESHOLD;
> @@ -827,6 +829,8 @@ static struct iw_statistics *bcm43xx_get
> 	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
> 	struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
> 	struct iw_statistics *wstats;
> +	struct ieee80211_network *network = NULL;
> +	static int tmp_level = 0;
> 
> 	wstats = &bcm->stats.wstats;
> 	if (!mac->associated) {
> @@ -849,11 +853,19 @@ static struct iw_statistics *bcm43xx_get
> 		return wstats;
> 	}
> 	/* fill in the real statistics when iface associated */
> -	wstats->qual.qual = 100;     // TODO: get the real signal quality
> -	wstats->qual.level = 3 - bcm->stats.link_quality;
> +	list_for_each_entry(network, &mac->ieee->network_list, list) {
> +		if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
> +			if (!tmp_level)		/* get initial value */
> +				tmp_level = network->stats.rssi;
> +			else			/* smooth results */
> +				tmp_level = (7 * tmp_level + network->stats.rssi)/8;
> +			break;
> +		}
> +	}

You need to lock the ieee80211 lock here. Otherwise it might race and crash,
if some workqueue modifies the list inbetween.

> +	wstats->qual.level = tmp_level;
> +	wstats->qual.qual = 100 + tmp_level - RSSI_MAX; // TODO: get the real signal quality
> 	wstats->qual.noise = bcm->stats.noise;
> -	wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
> -		IW_QUAL_NOISE_UPDATED;
> +	wstats->qual.updated = IW_QUAL_ALL_UPDATED;
> 	wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
> 	wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
> 	wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;


-- 
Greetings Michael.

^ permalink raw reply

* Re: bcm43xx: "transmit timed out" and apparent hang with "preemptible periodic work" patches
From: Michael Buesch @ 2006-06-29 15:07 UTC (permalink / raw)
  To: Paul Collins; +Cc: bcm43xx-dev, netdev, linville
In-Reply-To: <871wt8xtc9.fsf@briny.internal.ondioline.org>

On Thursday 29 June 2006 10:24, Paul Collins wrote:
> Michael Buesch <mb@bu3sch.de> writes:
> 
> > On Monday 26 June 2006 14:43, Michael Buesch wrote:
> >> Try to get more logs.
> >> I suggest to do a netconsole for logging.
> >
> > Also note that current softmac trees have a patch missing.
> > It seems it got lost somewhere after my merge request.
> > I already contacted John in private for this, but no reply, yet.
> > The patch is attached. Maybe it fixes your issue.
> 
> On a preempt kernel I can trigger the hang easily,

How? I need to reproduce it to get a clue and fix it. :)
I have no idea where it might come from (I don't even know
what exactly happens).

And please provide a _full_ dmesg log without comments inbetween
after triggering the hang (with a full Controller Restart cycle).

-- 
Greetings Michael.

^ permalink raw reply

* Re: 2.6.17.1: fails to fully get webpage
From: Bill Davidsen @ 2006-06-29 14:50 UTC (permalink / raw)
  To: CaT; +Cc: linux-kernel, netdev
In-Reply-To: <20060629041827.GJ2149@zip.com.au>

CaT wrote:
> On Wed, Jun 28, 2006 at 08:47:09PM -0700, David Miller wrote:
>> You can save yourself that hassle by informing the site admin
>> of the affected site that they have a firewall that misinterprets
>> the RFC standard window scaling field of the TCP headers.  These
>> devices assume it is zero because they don't remember the window
>> scale negotiated at the beginning of the TCP connection.
>>
>> Your TCP performance will suffer greatly if you disable window
>> scaling across the board.  It means that only a 64K window will
>> be usable by TCP, and you'll not be able to fill the pipe.
>>
>> Please don't use a screwdriver to pound in a nail :)
> 
> Indeed. The hassle I'm thinking of is the reverse situation (and please
> correct me if this does not apply). Say for example I run a web server.
> I have customers and they have customers (lets call them CCs :). Somewhere
> along the path between me and CCs there is such a misbehaving device.
> The CCs try to get to my customers website and fail (I assume). If my
> assumption is right, what's the probability of the CCs ever informing my
> customer that there is a problem? I think it's more likely they would
> just move on to another site offering the same thing, especially since
> they would mostlikely need to load the site in order to get the
> appropriate contact details.
> 
> Basically the mostlikely end-result is I don't know what there is a
> problem and my customer doesn't know that there is a problem but they're
> just not getting as many hits to their site that they otherwise would.
> 
> Ofcourse, this all depends if such a situation is possible. If it is
> possible would it affect dns and mail in a similar manner too?
> 
I'm glad David Miller clarified this, because I was about to send a 
"don't do that" followup ;-)

But your example is misleading, or at least doesn't reflect customers I 
know. While a few clients with broken network connections may be 
unhappy, disabling scaling will make your web server really, really, 
slow, and that will make everyone unhappy. Particularly if the web 
content is flash or 2MB jpegs, or other ill-chosen stuff. You don't want 
people to think you are running at dial-up speeds.

-- 
Bill Davidsen <davidsen@tmr.com>
   Obscure bug of 2004: BASH BUFFER OVERFLOW - if bash is being run by a
normal user and is setuid root, with the "vi" line edit mode selected,
and the character set is "big5," an off-by-one errors occurs during
wildcard (glob) expansion.



^ permalink raw reply

* Re: [Acx100-users] Denis Vlasenko, where are you? (mail bounced)
From: Andreas Mohr @ 2006-06-29 14:47 UTC (permalink / raw)
  To: acx100-users; +Cc: acx100-devel, netdev, linux-kernel
In-Reply-To: <20060629144233.GB24463@tuxdriver.com>

Hi,

On Thu, Jun 29, 2006 at 10:42:39AM -0400, John W. Linville wrote:
> If anyone knows how to get in touch w/ Denis, I'd appreciate it...

He sent me (and few other addresses) his new address recently
(*important* mails only!):

vda.linux AT a server called googlemail.com

(he got a new job and moved)

Andreas Mohr

Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642

^ permalink raw reply

* ACX100 (softmac-based) driver ready to merge, but is it legal? -- Re: wireless (was Re: 2.6.18 -mm merge plans)
From: John W. Linville @ 2006-06-29 14:26 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: Denis Vlasenko, Carlos Martin, Andreas Mohr, acx100-devel,
	acx100-users, Arjan van de Ven, Adrian Bunk, Alan Cox,
	Christoph Hellwig, linux-os (Dick Johnson), Evgeniy Polyakov,
	Jeff Garzik, Andrew Morton, Linus Torvalds
In-Reply-To: <1149524691.30554.23.camel@localhost.localdomain>

On Mon, Jun 05, 2006 at 05:24:51PM +0100, Alan Cox wrote:
> Ar Llu, 2006-06-05 am 09:27 -0400, ysgrifennodd John W. Linville:
> > Does not the Signed-off-by: line on a patch submission give us some
> > level of "good faith" protection?
> > 
> > I'm tempted to take contributors at their word, that they have produced
> > their own work and not copied from others.  What else do we need?
> 
> To keep an eye out for problems. Given the questions raised the tiacx
> people need to clarify their position and someone needs to look into it.
> Until that is done it certainly isn't "good faith" any more.

I apologize for the long copy list.  I have tried to include all
known interested parties.

This is a follow-up to a thread started by Andrew a few weeks ago
about what should be merged for 2.6.18.  One of the topics he cited
was the ACX100 driver which he has carried in -mm for quite some time.
I have a slightly different (softmac based) version of that driver
in wireless-2.6 which I think is worth merging now.

In the aforementioned thread, some questions were raised about the
legality of the ACX100 driver (i.e. tiacx) code base, but no one
had any specific points other than that it is not 100% "clean room"
derived.  Others point-out that this is not strictly a requirement.
The matter dropped without a strong defense from the tiacx team.

I hereby invite the tiacx team to defend their work by making public,
affirmative statements indicating a) how they produced their code; and,
b) that they have the legal right to license it as part of the Linux
kernel under the GPL.  As an incentive to this, I have already made
the necessary preparations for this driver to be merged immediately.

This is the softmac-based tiacx that has been in wireless-2.6 for
some time, with the addition of a few patches that akpm had in -mm
which I did not previously have.  For easy review, a tarball with
the full driver is available here:

	http://www.kernel.org/pub/linux/kernel/people/linville/tiacx.tar.gz

A git pull request follows.  I am confident that if the legal status
of this code can be confirmed, it will be merged upstream ASAP.

Comments welcome!

Thanks,

John

---

The following changes since commit 70a332b048e4d90635dfa47fc5d91cf87b5cc3a5:
  John W. Linville:
        softmac: fix build-break from 881ee6999d66c8fc903b429b73bbe6045b38c549

are found in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git tiacx

Andreas Mohr:
      tiacx: implement much more flexible firmware statistics parsing

Andrew Morton:
      tiacx: pci build fix

Carlos Martin:
      tiacx: fix breakage of "Get rid of circular list of adev's"
      tiacx: split module into acx-common + acx-pci + acx-usb

Denis Vlasenko:
      acxsm: merge from acx 0.3.32
      tiacx: revert "neither PCI nor USB is selected" change
      tiacx: Change acx_ioctl_{get,set}_encode to use kernel 80211 stack
      fix tiacx on alpha
      tiacx: fix attribute packed warnings

John W. Linville:
      wireless: add acx driver
      tiacx: Let only ACX_PCI/ACX_USB be user-visible
      tiacx: support ia64

 drivers/net/wireless/Kconfig             |    1 
 drivers/net/wireless/Makefile            |    2 
 drivers/net/wireless/tiacx/Changelog     |  114 
 drivers/net/wireless/tiacx/Kconfig       |   65 
 drivers/net/wireless/tiacx/Makefile      |    6 
 drivers/net/wireless/tiacx/README        |   61 
 drivers/net/wireless/tiacx/acx.h         |   11 
 drivers/net/wireless/tiacx/acx_config.h  |   40 
 drivers/net/wireless/tiacx/acx_func.h    |  598 ++
 drivers/net/wireless/tiacx/acx_struct.h  | 2048 ++++++++
 drivers/net/wireless/tiacx/common.c      | 7542 ++++++++++++++++++++++++++++++
 drivers/net/wireless/tiacx/ioctl.c       | 2738 +++++++++++
 drivers/net/wireless/tiacx/pci.c         | 4243 +++++++++++++++++
 drivers/net/wireless/tiacx/setrate.c     |  213 +
 drivers/net/wireless/tiacx/usb.c         | 1954 ++++++++
 drivers/net/wireless/tiacx/wlan.c        |  422 ++
 drivers/net/wireless/tiacx/wlan_compat.h |  267 +
 drivers/net/wireless/tiacx/wlan_hdr.h    |  497 ++
 drivers/net/wireless/tiacx/wlan_mgmt.h   |  582 ++
 19 files changed, 21404 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/wireless/tiacx/Changelog
 create mode 100644 drivers/net/wireless/tiacx/Kconfig
 create mode 100644 drivers/net/wireless/tiacx/Makefile
 create mode 100644 drivers/net/wireless/tiacx/README
 create mode 100644 drivers/net/wireless/tiacx/acx.h
 create mode 100644 drivers/net/wireless/tiacx/acx_config.h
 create mode 100644 drivers/net/wireless/tiacx/acx_func.h
 create mode 100644 drivers/net/wireless/tiacx/acx_struct.h
 create mode 100644 drivers/net/wireless/tiacx/common.c
 create mode 100644 drivers/net/wireless/tiacx/ioctl.c
 create mode 100644 drivers/net/wireless/tiacx/pci.c
 create mode 100644 drivers/net/wireless/tiacx/setrate.c
 create mode 100644 drivers/net/wireless/tiacx/usb.c
 create mode 100644 drivers/net/wireless/tiacx/wlan.c
 create mode 100644 drivers/net/wireless/tiacx/wlan_compat.h
 create mode 100644 drivers/net/wireless/tiacx/wlan_hdr.h
 create mode 100644 drivers/net/wireless/tiacx/wlan_mgmt.h

The complete (history-free) is available here:

	http://www.kernel.org/pub/linux/kernel/people/linville/tiacx.patch.gz

-- 
John W. Linville
linville@tuxdriver.com

^ permalink raw reply

* Re: TOE, etc.
From: Steve Wise @ 2006-06-29 14:09 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Caitlin Bestler, David Miller, herbert, netdev
In-Reply-To: <44A3140A.1040901@pobox.com>


> 
> > But back on the main point, if implementing SCSI services over a
> > TCP connection is acceptable even though it does not use a kernel
> > socket, why would it not be acceptable to implement RDMA services
> > over a TCP connection without using a kernel socket?
> 
> Because SCSI doesn't force nasty hooks into the net stack to allow for 
> sharing of resources with a proprietary black box of unknown quality.
> 
> 	Jeff
> 

The netevent notifier patch in question seemed to be reasonable hooks
for notifying kernel and user mode modules of certain network events.
In fact, it went through 3 review cycles and was improved by feedback
from Dave and others.  eg: It was integrated with netlink to provide
user mode notifications.  

Then someone says 'TOE' and suddenly the hooks are nasty?


Steve.


^ permalink raw reply

* Re: [RFT PATCH] pcnet32:  NAPI support
From: Lennart Sorensen @ 2006-06-29 12:58 UTC (permalink / raw)
  To: Don Fry; +Cc: netdev
In-Reply-To: <20060628165541.GA16601@us.ibm.com>

On Wed, Jun 28, 2006 at 09:55:41AM -0700, Don Fry wrote:
> Yes, I saw the debug statements when creating the email and was too lazy
> to remove them and create a new patch.  The patch needs to be broken up
> into functional pieces anyway, so since it has passed all of my testing
> as well, I will start on that...

So it might make 2.6.18 then? :)

I just updated the driver in my 2.6.16 kernel to the 2.6.17 version and
applied your patch, and then added my own weird stuff that no one else
will want.

Len Sorensen

^ permalink raw reply

* Re: Network namespaces a path to mergable code.
From: Daniel Lezcano @ 2006-06-29  9:42 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Andrey Savochkin, linux-kernel, netdev, serue, haveblue, clg,
	Andrew Morton, dev, herbert, devel, sam, viro, Alexey Kuznetsov
In-Reply-To: <m11wt8erjv.fsf@ebiederm.dsl.xmission.com>

Eric W. Biederman wrote:
>>When an outgoing packet has the loopback destination addres, the
>>skbuff is filled with the network namespace. So the loopback packets
>>never go outside the namespace. This approach facilitate the migration
>>of loopback because identification is done by network namespace and
>>not by address. The loopback has been benchmarked by tbench and the
>>overhead is roughly 1.5 %
> 
> 
> Ugh.  1.5% is noticeable.

We will see with all private network namespace ...
> 
> I think it is cheaper to have one loopback device per namespace.
> Which removes the need for a skbuff tag.

Yes, probably.

^ permalink raw reply

* Netchannels: progress report.
From: Evgeniy Polyakov @ 2006-06-29  9:38 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev
In-Reply-To: <20060613173321.GA648@2ka.mipt.ru>

Implemented alternative userspace TCP/IP stack which supports:
1. TCP/UDP/IP sending and receiving.
2. Timestamp, window scaling and MSS TCP options.
3. Slow start and congestion control (trivial though).
4. PAWS.
5. Trivial route table (route list) including static MAC cache.
6. IP and ethernet frame processing.
7. netchannel-like interface for sending/receiving/connecting.

Some fancy algos (very simple) were imported into ACK generation and
sending data combining code.

I started to put that code into kernel netchannel [1] implementation.
Receiving is fully supported with 3-4 MB (2<<20 bytes) per second 
performance win over usual socket code (tuned for maximum performance).

Sender of data is wrong for benchmarking purposes though: it is netcat
which reads data from stdin (where big file is being read).

After some investigation it was proven that there is some bottleneck in
the sending size.

Socket -> socket:      ~69-70 MB/sec
Socket -> netchannel:  ~72-73 MB/sec

Next thing is to test netchannel sending support, which was only tested
with userspace implementation over packet socket.

Attached development patch with a lot of debug cruft for curious reader.

I received several very positive feedbacks from various people about this
project, thank you.

Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>

diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index f48bef1..7a4a758 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -315,3 +315,5 @@ ENTRY(sys_call_table)
 	.long sys_splice
 	.long sys_sync_file_range
 	.long sys_tee			/* 315 */
+	.long sys_vmsplice
+	.long sys_netchannel_control
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 5a92fed..fdfb997 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -696,4 +696,5 @@ #endif
 	.quad sys_sync_file_range
 	.quad sys_tee
 	.quad compat_sys_vmsplice
+	.quad sys_netchannel_control
 ia32_syscall_end:		
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index eb4b152..777cd85 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -322,8 +322,9 @@ #define __NR_splice		313
 #define __NR_sync_file_range	314
 #define __NR_tee		315
 #define __NR_vmsplice		316
+#define __NR_netchannel_control	317
 
-#define NR_syscalls 317
+#define NR_syscalls 318
 
 /*
  * user-visible error numbers are in the range -1 - -128: see
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index feb77cb..08c230e 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -617,8 +617,10 @@ #define __NR_sync_file_range	277
 __SYSCALL(__NR_sync_file_range, sys_sync_file_range)
 #define __NR_vmsplice		278
 __SYSCALL(__NR_vmsplice, sys_vmsplice)
+#define __NR_netchannel_control	279
+__SYSCALL(__NR_vmsplice, sys_netchannel_control)
 
-#define __NR_syscall_max __NR_vmsplice
+#define __NR_syscall_max __NR_netchannel_control
 
 #ifndef __NO_STUBS
 
diff --git a/include/linux/netchannel.h b/include/linux/netchannel.h
new file mode 100644
index 0000000..482c202
--- /dev/null
+++ b/include/linux/netchannel.h
@@ -0,0 +1,140 @@
+/*
+ * 	netchannel.h
+ * 
+ * 2006 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __NETCHANNEL_H
+#define __NETCHANNEL_H
+
+#include <linux/types.h>
+
+enum netchannel_commands {
+	NETCHANNEL_CREATE = 0,
+	NETCHANNEL_REMOVE,
+	NETCHANNEL_BIND,
+	NETCHANNEL_READ,
+	NETCHANNEL_DUMP,
+	NETCHANNEL_CONNECT,
+};
+
+enum netchannel_type {
+	NETCHANNEL_COPY_USER = 0,
+	NETCHANNEL_MMAP,
+	NETCHANEL_VM_HACK,
+};
+
+struct unetchannel
+{
+	__u32			faddr, laddr;		/* foreign/local hashes */
+	__u16			fport, lport;		/* foreign/local ports */
+	__u8			proto;			/* IP protocol number */
+	__u8			type;			/* Netchannel type */
+	__u8			memory_limit_order;	/* Memor limit order */
+	__u8			init_stat_work;		/* Start statistic dumping */
+};
+
+struct unetchannel_control
+{
+	struct unetchannel	unc;
+	__u32			cmd;
+	__u32			len;
+	__u32			flags;
+	__u32			timeout;
+	unsigned int		fd;
+};
+
+#ifdef __KERNEL__
+
+struct netchannel_stat
+{
+	u64			enter;
+	u64			ready;
+	u64			recv;
+	u64			empty;
+	u64			null;
+	u64			backlog;
+	u64			backlog_err;
+	u64			eat;
+};
+
+struct netchannel;
+
+struct common_protocol
+{
+	unsigned int		size;
+
+	int 			(*connect)(struct netchannel *);
+	int 			(*destroy)(struct netchannel *);
+
+	int 			(*process_in)(struct netchannel *, void *, unsigned int);
+	int 			(*process_out)(struct netchannel *, void *, unsigned int);
+};
+
+struct netchannel
+{
+	struct hlist_node	node;
+	atomic_t		refcnt;
+	struct rcu_head		rcu_head;
+	struct unetchannel	unc;
+	unsigned long		hit;
+
+	struct page *		(*nc_alloc_page)(unsigned int size);
+	void			(*nc_free_page)(struct page *page);
+	int			(*nc_read_data)(struct netchannel *, unsigned int *timeout, unsigned int *len, void *arg);
+
+	struct sk_buff_head 	recv_queue;
+	wait_queue_head_t	wait;
+
+	unsigned int		qlen;
+
+	void			*priv;
+
+	struct inode 		*inode;
+
+	struct work_struct	work;
+
+	struct netchannel_stat	stat;
+
+	struct common_protocol	*proto;
+	struct dst_entry	*dst;
+};
+
+struct netchannel_cache_head
+{
+	struct hlist_head	head;
+	struct mutex		mutex;
+};
+
+#define NETCHANNEL_MAX_ORDER	31
+#define NETCHANNEL_MIN_ORDER	PAGE_SHIFT
+
+struct netchannel_mmap
+{
+	struct page		**page;
+	unsigned int		pnum;
+	unsigned int		poff;
+};
+
+extern struct common_protocol atcp_common_protocol;
+
+extern struct sk_buff *netchannel_get_skb(struct netchannel *nc, unsigned int *timeout, int *error);
+struct dst_entry *netchannel_route_get_raw(struct netchannel *nc);
+
+#endif /* __KERNEL__ */
+#endif /* __NETCHANNEL_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a461b51..9924911 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -684,6 +684,15 @@ extern void		dev_queue_xmit_nit(struct s
 
 extern void		dev_init(void);
 
+#ifdef CONFIG_NETCHANNEL
+extern int netchannel_recv(struct sk_buff *skb);
+#else
+static int netchannel_recv(struct sk_buff *skb) 
+{ 
+	return -1;
+}
+#endif
+
 extern int		netdev_nit;
 extern int		netdev_budget;
 
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
@@ -314,6 +315,18 @@ static inline struct sk_buff *alloc_skb(
 	return __alloc_skb(size, priority, 0);
 }
 
+#ifdef CONFIG_NETCHANNEL
+struct unetchannel;
+extern struct sk_buff *netchannel_alloc(struct unetchannel *unc, unsigned int header_size, 
+		unsigned int total_size, gfp_t gfp_mask);
+#else
+static struct sk_buff *netchannel_alloc(void *unc, unsigned int header_size, 
+		unsigned int total_size, gfp_t gfp_mask)
+{
+	return NULL;
+}
+#endif
+
 static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
 					       gfp_t priority)
 {
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 3996960..8c22875 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -582,4 +582,6 @@ asmlinkage long sys_tee(int fdin, int fd
 asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
 					unsigned int flags);
 
+asmlinkage long sys_netchannel_control(void __user *arg);
+
 #endif
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 5433195..1747fc3 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -132,3 +132,5 @@ cond_syscall(sys_mincore);
 cond_syscall(sys_madvise);
 cond_syscall(sys_mremap);
 cond_syscall(sys_remap_file_pages);
+
+cond_syscall(sys_netchannel_control);
diff --git a/net/Kconfig b/net/Kconfig
index 4193cdc..465e37b 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -66,6 +66,14 @@ source "net/ipv6/Kconfig"
 
 endif # if INET
 
+config NETCHANNEL
+	bool "Network channels"
+	---help---
+	  Network channels are peer-to-peer abstraction, which allows to create
+	  high performance communications. 
+	  Main advantages are unified address cache, protocol processing moved
+	  to userspace, receiving zero-copy support and other interesting features.
+
 menuconfig NETFILTER
 	bool "Network packet filtering (replaces ipchains)"
 	---help---
diff --git a/net/core/Makefile b/net/core/Makefile
index 79fe12c..7119812 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PKTGEN) += pktgen.o
 obj-$(CONFIG_WIRELESS_EXT) += wireless.o
 obj-$(CONFIG_NETPOLL) += netpoll.o
+obj-$(CONFIG_NETCHANNEL) += netchannel.o
diff --git a/net/core/dev.c b/net/core/dev.c
index 9ab3cfa..2721111 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1712,6 +1712,10 @@ #endif
 		}
 	}
 
+	ret = netchannel_recv(skb);
+	if (!ret)
+		goto out;
+
 #ifdef CONFIG_NET_CLS_ACT
 	if (pt_prev) {
 		ret = deliver_skb(skb, pt_prev, orig_dev);
diff --git a/net/core/netchannel.c b/net/core/netchannel.c
new file mode 100644
index 0000000..7c4ad1a
--- /dev/null
+++ b/net/core/netchannel.c
@@ -0,0 +1,1141 @@
+/*
+ * 	netchannel.c
+ * 
+ * 2006 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/unistd.h>
+#include <linux/linkage.h>
+#include <linux/notifier.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/file.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/highmem.h>
+#include <linux/workqueue.h>
+#include <linux/netchannel.h>
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
+#include <linux/udp.h>
+
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <net/addrconf.h>
+
+#include <asm/uaccess.h>
+
+static unsigned int netchannel_hash_order = 8;
+static struct netchannel_cache_head ***netchannel_hash_table;
+static kmem_cache_t *netchannel_cache;
+
+static int netchannel_inetaddr_notifier_call(struct notifier_block *, unsigned long, void *);
+static struct notifier_block netchannel_inetaddr_notifier = {
+	.notifier_call = &netchannel_inetaddr_notifier_call
+};
+
+#ifdef CONFIG_IPV6
+static int netchannel_inet6addr_notifier_call(struct notifier_block *, unsigned long, void *);
+static struct notifier_block netchannel_inet6addr_notifier = {
+	.notifier_call = &netchannel_inet6addr_notifier_call
+};
+#endif
+
+static inline unsigned int netchannel_hash(struct unetchannel *unc)
+{
+	unsigned int h = (unc->faddr ^ unc->fport) ^ (unc->laddr ^ unc->lport);
+	h ^= h >> 16;
+	h ^= h >> 8;
+	h ^= unc->proto;
+	return h & ((1 << 2*netchannel_hash_order) - 1);
+}
+
+static inline void netchannel_convert_hash(unsigned int hash, unsigned int *col, unsigned int *row)
+{
+	*row = hash & ((1 << netchannel_hash_order) - 1);
+	*col = (hash >> netchannel_hash_order) & ((1 << netchannel_hash_order) - 1);
+}
+
+static struct netchannel_cache_head *netchannel_bucket(struct unetchannel *unc)
+{
+	unsigned int hash = netchannel_hash(unc);
+	unsigned int col, row;
+
+	netchannel_convert_hash(hash, &col, &row);
+	return netchannel_hash_table[col][row];
+}
+
+static inline int netchannel_hash_equal_full(struct unetchannel *unc1, struct unetchannel *unc2)
+{
+	return (unc1->fport == unc2->fport) && (unc1->faddr == unc2->faddr) &&
+				(unc1->lport == unc2->lport) && (unc1->laddr == unc2->laddr) && 
+				(unc1->proto == unc2->proto);
+}
+
+static inline int netchannel_hash_equal_dest(struct unetchannel *unc1, struct unetchannel *unc2)
+{
+	return ((unc1->fport == unc2->fport) && (unc1->faddr == unc2->faddr) && (unc1->proto == unc2->proto));
+}
+
+static struct netchannel *netchannel_check_dest(struct unetchannel *unc, struct netchannel_cache_head *bucket)
+{
+	struct netchannel *nc;
+	struct hlist_node *node;
+	int found = 0;
+	
+	hlist_for_each_entry_rcu(nc, node, &bucket->head, node) {
+		if (netchannel_hash_equal_dest(&nc->unc, unc)) {
+			found = 1;
+			break;
+		}
+	}
+
+	return (found)?nc:NULL;
+}
+
+static struct netchannel *netchannel_check_full(struct unetchannel *unc, struct netchannel_cache_head *bucket)
+{
+	struct netchannel *nc;
+	struct hlist_node *node;
+	int found = 0;
+
+	hlist_for_each_entry_rcu(nc, node, &bucket->head, node) {
+		if (netchannel_hash_equal_full(&nc->unc, unc)) {
+			found = 1;
+			break;
+		}
+	}
+
+	return (found)?nc:NULL;
+}
+
+static void netchannel_mmap_cleanup(struct netchannel *nc)
+{
+	unsigned int i;
+	struct netchannel_mmap *m = nc->priv;
+
+	for (i=0; i<m->pnum; ++i)
+		__free_page(m->page[i]);
+
+	kfree(m);
+}
+
+static void netchannel_cleanup(struct netchannel *nc)
+{
+	kfree(nc->proto);
+	switch (nc->unc.type) {
+		case NETCHANNEL_COPY_USER:
+			break;
+		case NETCHANNEL_MMAP:
+			netchannel_mmap_cleanup(nc);
+			break;
+		default:
+			break;
+	}
+}
+
+static void netchannel_free_rcu(struct rcu_head *rcu)
+{
+	struct netchannel *nc = container_of(rcu, struct netchannel, rcu_head);
+
+	netchannel_cleanup(nc);
+	kmem_cache_free(netchannel_cache, nc);
+}
+
+static inline void netchannel_get(struct netchannel *nc)
+{
+	atomic_inc(&nc->refcnt);
+}
+
+static inline void netchannel_put(struct netchannel *nc)
+{
+	if (atomic_dec_and_test(&nc->refcnt))
+		call_rcu(&nc->rcu_head, &netchannel_free_rcu);
+}
+
+static inline void netchannel_dump_info_unc(struct unetchannel *unc, char *prefix, unsigned long hit, int err)
+{
+	printk(KERN_NOTICE "netchannel: %s %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u, "
+			"proto: %u, type: %u, order: %u, hit: %lu, err: %d.\n",
+			prefix, NIPQUAD(unc->laddr), ntohs(unc->lport), NIPQUAD(unc->faddr), ntohs(unc->fport), 
+			unc->proto, unc->type, unc->memory_limit_order, hit, err);
+}
+
+static int netchannel_convert_skb_ipv6(struct sk_buff *skb, struct unetchannel *unc)
+{
+	/*
+	 * Hash IP addresses into src/dst. Setup TCP/UDP ports.
+	 * Not supported yet.
+	 */
+	return -1;
+}
+
+static int netchannel_convert_skb_ipv4(struct sk_buff *skb, struct unetchannel *unc)
+{
+	struct iphdr *iph;
+	u32 len;
+
+	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		goto inhdr_error;
+
+	iph = skb->nh.iph;
+
+	if (iph->ihl < 5 || iph->version != 4)
+		goto inhdr_error;
+
+	if (!pskb_may_pull(skb, iph->ihl*4))
+		goto inhdr_error;
+
+	iph = skb->nh.iph;
+
+	if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
+		goto inhdr_error;
+
+	len = ntohs(iph->tot_len);
+	if (skb->len < len || len < (iph->ihl*4))
+		goto inhdr_error;
+
+	if (pskb_trim_rcsum(skb, len))
+		goto inhdr_error;
+
+	unc->faddr = iph->saddr;
+	unc->laddr = iph->daddr;
+	unc->proto = iph->protocol;
+
+	len = skb->len;
+
+	skb->h.raw = skb->nh.raw + iph->ihl*4;
+
+	switch (unc->proto) {
+		case IPPROTO_TCP:
+		case IPPROTO_UDP:
+			unc->fport = ((u16 *)skb->h.raw)[0];
+			unc->lport = ((u16 *)skb->h.raw)[1];
+			break;
+		default:
+			goto inhdr_error;
+	}
+
+	return 0;
+
+inhdr_error:
+	return -1;
+}
+
+static int netchannel_convert_skb(struct sk_buff *skb, struct unetchannel *unc)
+{
+	if (skb->pkt_type == PACKET_OTHERHOST)
+		return -1;
+
+	switch (ntohs(skb->protocol)) {
+		case ETH_P_IP:
+			return netchannel_convert_skb_ipv4(skb, unc);
+		case ETH_P_IPV6:
+			return netchannel_convert_skb_ipv6(skb, unc);
+		default:
+			return -1;
+	}
+}
+
+/*
+ * By design netchannels allow to "allocate" data
+ * not only from SLAB cache, but get it from mapped area
+ * or from VFS cache (requires process' context or preallocation).
+ */
+struct sk_buff *netchannel_alloc(struct unetchannel *unc, unsigned int header_size, 
+		unsigned int total_size, gfp_t gfp_mask)
+{
+	struct netchannel *nc;
+	struct netchannel_cache_head *bucket;
+	int err;
+	struct sk_buff *skb = NULL;
+	unsigned int size, pnum, i;
+
+	skb = alloc_skb(header_size, gfp_mask);
+	if (!skb)
+		return NULL;
+
+	rcu_read_lock();
+	bucket = netchannel_bucket(unc);
+	nc = netchannel_check_full(unc, bucket);
+	if (!nc) {
+		err = -ENODEV;
+		goto err_out_free_skb;
+	}
+
+	if (!nc->nc_alloc_page || !nc->nc_free_page) {
+		err = -EINVAL;
+		goto err_out_free_skb;
+	}
+
+	netchannel_get(nc);
+
+	size = total_size - header_size;
+	pnum = PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+	for (i=0; i<pnum; ++i) {
+		unsigned int cs = min_t(unsigned int, PAGE_SIZE, size);
+		struct page *page;
+
+		page = nc->nc_alloc_page(cs);
+		if (!page)
+			break;
+		
+		skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, 0, cs);
+		
+		skb->len	+= cs;
+		skb->data_len	+= cs;
+		skb->truesize	+= cs;
+
+		size -= cs;
+	}
+
+	if (i < pnum) {
+		pnum = i;
+		err = -ENOMEM;
+		goto err_out_free_frags;
+	}
+
+	rcu_read_unlock();
+
+	return skb;
+
+err_out_free_frags:
+	for (i=0; i<pnum; ++i) {
+		unsigned int cs = skb_shinfo(skb)->frags[i].size;
+		struct page *page = skb_shinfo(skb)->frags[i].page;
+		
+		nc->nc_free_page(page);
+
+		skb->len	-= cs;
+		skb->data_len	-= cs;
+		skb->truesize	-= cs;
+	}
+
+err_out_free_skb:
+	kfree_skb(skb);
+	return NULL;
+}
+
+int netchannel_recv(struct sk_buff *skb)
+{
+	struct netchannel *nc;
+	struct unetchannel unc;
+	struct netchannel_cache_head *bucket;
+	int err;
+
+	if (!netchannel_hash_table)
+		return -ENODEV;
+
+	rcu_read_lock();
+
+	err = netchannel_convert_skb(skb, &unc);
+	if (err)
+		goto unlock;
+
+	bucket = netchannel_bucket(&unc);
+	nc = netchannel_check_full(&unc, bucket);
+	if (!nc) {
+		err = -ENODEV;
+		goto unlock;
+	}
+
+	nc->hit++;
+#if 0
+	if (nc->qlen + skb->len > (1 << nc->unc.memory_limit_order)) {
+		kfree_skb(skb);
+		err = 0;
+		goto unlock;
+	}
+#endif
+	nc->qlen += skb->len;
+	skb_queue_tail(&nc->recv_queue, skb);
+	//printk("\n%s: skb: %p, size: %u.\n", __func__, skb, skb->len);
+	wake_up(&nc->wait);
+
+unlock:
+	rcu_read_unlock();
+	
+	return err;
+}
+
+static int netchannel_wait_for_packet(struct netchannel *nc, long *timeo_p)
+{
+	int error = 0;
+	DEFINE_WAIT(wait);
+
+	prepare_to_wait_exclusive(&nc->wait, &wait, TASK_INTERRUPTIBLE);
+
+	if (skb_queue_empty(&nc->recv_queue)) {
+		if (signal_pending(current))
+			goto interrupted;
+
+		*timeo_p = schedule_timeout(*timeo_p);
+	}
+out:
+	finish_wait(&nc->wait, &wait);
+	return error;
+interrupted:
+	error = (*timeo_p == MAX_SCHEDULE_TIMEOUT) ? -ERESTARTSYS : -EINTR;
+	goto out;
+}
+
+struct sk_buff *netchannel_get_skb(struct netchannel *nc, unsigned int *timeout, int *error)
+{
+	struct sk_buff *skb = NULL;
+	long tm = *timeout;
+
+	*error = 0;
+
+	while (1) {
+		skb = skb_dequeue(&nc->recv_queue);
+		if (skb) {
+			nc->qlen -= skb->len;
+			break;
+		}
+
+		if (*timeout) {
+			*error = netchannel_wait_for_packet(nc, &tm);
+			if (*error) {
+				*timeout = tm;
+				skb = skb_dequeue(&nc->recv_queue);
+				break;
+			}
+			tm = *timeout;
+		} else {
+			*error = -EAGAIN;
+			break;
+		}
+	}
+
+	return skb;
+}
+
+static int netchannel_copy_to_user_tcp(struct netchannel *nc, unsigned int *timeout, unsigned int *len, void *buf)
+{
+	int ret = nc->proto->process_in(nc, buf, *len);
+	if (ret < 0)
+		return ret;
+	*len = ret;
+	return 0;
+}
+
+static int netchannel_copy_to_user(struct netchannel *nc, unsigned int *timeout, unsigned int *len, void *arg)
+{
+	unsigned int copied;
+	struct sk_buff *skb;
+	struct iovec to;
+	int err;
+
+	skb = netchannel_get_skb(nc, timeout, &err);
+	if (!skb)
+		return err;
+
+	to.iov_base = arg;
+	to.iov_len = *len;
+
+	copied = skb->len;
+	if (copied > *len)
+		copied = *len;
+
+	if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+		err = skb_copy_datagram_iovec(skb, 0, &to, copied);
+	} else {
+		err = skb_copy_and_csum_datagram_iovec(skb,0, &to);
+	}
+
+	*len = (err == 0)?copied:0;
+
+	kfree_skb(skb);
+
+	return err;
+}
+
+int netchannel_skb_copy_datagram(const struct sk_buff *skb, int offset,
+			    void *to, int len)
+{
+	int start = skb_headlen(skb);
+	int i, copy = start - offset;
+
+	/* Copy header. */
+	if (copy > 0) {
+		if (copy > len)
+			copy = len;
+		memcpy(to, skb->data + offset, copy);
+
+		if ((len -= copy) == 0)
+			return 0;
+		offset += copy;
+		to += copy;
+	}
+
+	/* Copy paged appendix. Hmm... why does this look so complicated? */
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		int end;
+
+		BUG_TRAP(start <= offset + len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
+		if ((copy = end - offset) > 0) {
+			u8  *vaddr;
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+			struct page *page = frag->page;
+
+			if (copy > len)
+				copy = len;
+			vaddr = kmap(page);
+			memcpy(to, vaddr + frag->page_offset +
+					     offset - start, copy);
+			kunmap(page);
+			if (!(len -= copy))
+				return 0;
+			offset += copy;
+			to += copy;
+		}
+		start = end;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list = skb_shinfo(skb)->frag_list;
+
+		for (; list; list = list->next) {
+			int end;
+
+			BUG_TRAP(start <= offset + len);
+
+			end = start + list->len;
+			if ((copy = end - offset) > 0) {
+				if (copy > len)
+					copy = len;
+				if (netchannel_skb_copy_datagram(list,
+							    offset - start,
+							    to, copy))
+					goto fault;
+				if ((len -= copy) == 0)
+					return 0;
+				offset += copy;
+				to += copy;
+			}
+			start = end;
+		}
+	}
+	if (!len)
+		return 0;
+
+fault:
+	return -EFAULT;
+}
+
+static int netchannel_copy_to_mem(struct netchannel *nc, unsigned int *timeout, unsigned int *len, void *arg)
+{
+	struct netchannel_mmap *m = nc->priv;
+	unsigned int copied, skb_offset = 0;
+	struct sk_buff *skb;
+	int err;
+
+	skb = netchannel_get_skb(nc, timeout, &err);
+	if (!skb)
+		return err;
+
+	copied = skb->len;
+
+	while (copied) {
+		int pnum = ((m->poff % PAGE_SIZE) % m->pnum);
+		struct page *page = m->page[pnum];
+		void *page_map, *ptr;
+		unsigned int sz, left;
+
+		left = PAGE_SIZE - (m->poff % (PAGE_SIZE - 1));
+		sz = min_t(unsigned int, left, copied);
+
+		if (!sz) {
+			err = -ENOSPC;
+			goto err_out;
+		}
+
+		page_map = kmap_atomic(page, KM_USER0);
+		if (!page_map) {
+			err = -ENOMEM;
+			goto err_out;
+		}
+		ptr = page_map + (m->poff % (PAGE_SIZE - 1));
+
+		err = netchannel_skb_copy_datagram(skb, skb_offset, ptr, sz);
+		if (err) {
+			kunmap_atomic(page_map, KM_USER0);
+			goto err_out;
+		}
+		kunmap_atomic(page_map, KM_USER0);
+
+		copied -= sz;
+		m->poff += sz;
+		skb_offset += sz;
+#if 1
+		if (m->poff >= PAGE_SIZE * m->pnum) {
+			//netchannel_dump_info_unc(&nc->unc, "rewind", nc->hit, 0);
+			m->poff = 0;
+		}
+#endif
+	}
+	*len = skb->len;
+
+	err = 0;
+
+err_out:
+	kfree_skb(skb);
+
+	return err;
+}
+
+static int netchannel_mmap_setup(struct netchannel *nc)
+{
+	struct netchannel_mmap *m;
+	unsigned int i, pnum;
+
+	pnum = nc->unc.memory_limit_order - NETCHANNEL_MIN_ORDER;
+
+	m = kzalloc(sizeof(struct netchannel_mmap) + sizeof(struct page *) * pnum, GFP_KERNEL);
+	if (!m)
+		return -ENOMEM;
+
+	m->page = (struct page **)(m + 1);
+	m->pnum = pnum;
+
+	for (i=0; i<pnum; ++i) {
+		m->page[i] = alloc_page(GFP_KERNEL);
+		if (!m->page[i])
+			break;
+	}
+
+	if (i < pnum) {
+		pnum = i;
+		goto err_out_free;
+	}
+
+	nc->priv = m;
+
+	switch (nc->unc.proto) {
+		case IPPROTO_TCP:
+			nc->proto = kzalloc(atcp_common_protocol.size, GFP_KERNEL);
+			if (!nc->proto)
+				goto err_out_free;
+			memcpy(nc->proto, &atcp_common_protocol, sizeof(struct common_protocol));
+			nc->nc_read_data = &netchannel_copy_to_user_tcp;
+			break;
+		case IPPROTO_UDP:
+		default:
+			nc->nc_read_data = &netchannel_copy_to_mem;
+			break;
+	}
+
+	return 0;
+
+err_out_free:
+	for (i=0; i<pnum; ++i)
+		__free_page(m->page[i]);
+
+	kfree(m);
+
+	return -ENOMEM;
+	
+}
+
+static int netchannel_copy_user_setup(struct netchannel *nc)
+{
+	int ret = 0;
+	
+	switch (nc->unc.proto) {
+		case IPPROTO_UDP:
+			nc->nc_read_data = &netchannel_copy_to_user;
+			break;
+		case IPPROTO_TCP:
+			nc->proto = kzalloc(atcp_common_protocol.size, GFP_KERNEL);
+			if (!nc->proto) {
+				ret = -ENOMEM;
+				break;
+			}
+			memcpy(nc->proto, &atcp_common_protocol, sizeof(struct common_protocol));
+			nc->nc_read_data = &netchannel_copy_to_user_tcp;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+	}
+
+	return ret;
+}
+
+static int netchannel_setup(struct netchannel *nc)
+{
+	int ret = 0;
+
+	if (nc->unc.memory_limit_order > NETCHANNEL_MAX_ORDER)
+		nc->unc.memory_limit_order = NETCHANNEL_MAX_ORDER;
+
+	if (nc->unc.memory_limit_order < NETCHANNEL_MIN_ORDER)
+		nc->unc.memory_limit_order = NETCHANNEL_MIN_ORDER;
+	
+	switch (nc->unc.type) {
+		case NETCHANNEL_COPY_USER:
+			ret = netchannel_copy_user_setup(nc);
+			break;
+		case NETCHANNEL_MMAP:
+			ret = netchannel_mmap_setup(nc);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+	}
+
+	return ret;
+}
+
+static int netchannel_bind(struct unetchannel_control *ctl)
+{
+	struct netchannel *nc;
+	int err = -EINVAL, fput_needed;
+	struct netchannel_cache_head *bucket;
+	struct file *file;
+	struct inode *inode;
+
+	file = fget_light(ctl->fd, &fput_needed);
+	if (!file)
+		goto err_out_exit;
+
+	inode = igrab(file->f_dentry->d_inode);
+	if (!inode)
+		goto err_out_fput;
+
+	bucket = netchannel_bucket(&ctl->unc);
+	
+	mutex_lock(&bucket->mutex);
+	
+	nc = netchannel_check_full(&ctl->unc, bucket);
+	if (!nc) {
+		err = -ENODEV;
+		goto err_out_unlock;
+	}
+
+	nc->inode = inode;
+
+	fput_light(file, fput_needed);
+	mutex_unlock(&bucket->mutex);
+
+	return 0;
+
+err_out_unlock:
+	mutex_unlock(&bucket->mutex);
+err_out_fput:
+	fput_light(file, fput_needed);
+err_out_exit:
+	return err;
+}
+
+static void netchannel_dump_stat(struct netchannel *nc)
+{
+	printk(KERN_NOTICE "netchannel: enter: %llu, ready: %llu, recv: %llu, empty: %llu, null: %llu, backlog: %llu, backlog_err: %llu, eat: %llu.\n",
+			nc->stat.enter, nc->stat.ready, nc->stat.recv, nc->stat.empty, nc->stat.null, nc->stat.backlog,
+			nc->stat.backlog_err, nc->stat.eat);
+}
+
+static void netchannel_work(void *data)
+{
+	struct netchannel *nc = data;
+	
+	netchannel_dump_info_unc(&nc->unc, "work", nc->hit, 0);
+
+	if (nc->inode) {
+		struct socket *sock;
+		struct sock *sk;
+
+		sock = SOCKET_I(nc->inode);
+		if (!sock || !sock->sk)
+			goto out;
+
+		sk = sock->sk;
+		printk(KERN_NOTICE "netchannel: sk: %p, skb_qlen: %u, nc_qlen: %u.\n", 
+				sk, skb_queue_len(&nc->recv_queue), nc->qlen);
+	}
+	netchannel_dump_stat(nc);
+out:
+	schedule_delayed_work(&nc->work, msecs_to_jiffies(1000*nc->unc.init_stat_work));
+}
+
+static int netchannel_create(struct unetchannel *unc)
+{
+	struct netchannel *nc;
+	int err = -ENOMEM;
+	struct netchannel_cache_head *bucket;
+	
+	nc = kmem_cache_alloc(netchannel_cache, GFP_KERNEL);
+	if (!nc)
+		return -ENOMEM;
+
+	memset(nc, 0, sizeof(struct netchannel));
+	
+	nc->hit = 0;
+	skb_queue_head_init(&nc->recv_queue);
+	init_waitqueue_head(&nc->wait);
+	atomic_set(&nc->refcnt, 1);
+	memcpy(&nc->unc, unc, sizeof(struct unetchannel));
+
+	err = netchannel_setup(nc);
+	if (err)
+		goto err_out_free;
+
+	nc->dst = netchannel_route_get_raw(nc);
+	if (!nc->dst) {
+		err = -ENODEV;
+		goto err_out_cleanup;
+	}
+
+	bucket = netchannel_bucket(unc);
+
+	mutex_lock(&bucket->mutex);
+
+	if (netchannel_check_full(unc, bucket)) {
+		err = -EEXIST;
+		goto err_out_unlock;
+	}
+
+	hlist_add_head_rcu(&nc->node, &bucket->head);
+	err = 0;
+
+	mutex_unlock(&bucket->mutex);
+
+	netchannel_dump_info_unc(unc, "create", 0, err);
+
+	INIT_WORK(&nc->work, netchannel_work, nc);
+	if (nc->unc.init_stat_work)
+		schedule_delayed_work(&nc->work, msecs_to_jiffies(1000*nc->unc.init_stat_work));
+
+	return err;
+
+err_out_unlock:
+	mutex_unlock(&bucket->mutex);
+	dst_release(nc->dst);
+err_out_cleanup:
+	netchannel_cleanup(nc);
+err_out_free:
+	kmem_cache_free(netchannel_cache, nc);
+
+	return err;
+}
+
+static int netchannel_remove(struct unetchannel *unc)
+{
+	struct netchannel *nc;
+	int err = -ENODEV;
+	struct netchannel_cache_head *bucket;
+	unsigned long hit = 0;
+	
+	if (!netchannel_hash_table)
+		return -ENODEV;
+	
+	bucket = netchannel_bucket(unc);
+
+	mutex_lock(&bucket->mutex);
+
+	nc = netchannel_check_full(unc, bucket);
+	if (!nc)
+		nc = netchannel_check_dest(unc, bucket);
+
+	if (!nc)
+		goto out_unlock;
+	
+	hlist_del_rcu(&nc->node);
+	hit = nc->hit;
+
+	if (nc->unc.init_stat_work) {
+		cancel_rearming_delayed_work(&nc->work);
+		flush_scheduled_work();
+	}
+	
+	if (nc->inode) {
+		iput(nc->inode);
+		nc->inode = NULL;
+	}
+	dst_release(nc->dst);
+	
+	netchannel_put(nc);
+	err = 0;
+
+out_unlock:
+	mutex_unlock(&bucket->mutex);
+	netchannel_dump_info_unc(unc, "remove", hit, err);
+	return err;
+}
+
+static int netchannel_recv_data(struct unetchannel_control *ctl, void __user *data)
+{
+	int ret = -ENODEV;
+	struct netchannel_cache_head *bucket;
+	struct netchannel *nc;
+	
+	bucket = netchannel_bucket(&ctl->unc);
+
+	mutex_lock(&bucket->mutex);
+
+	nc = netchannel_check_full(&ctl->unc, bucket);
+	if (!nc)
+		nc = netchannel_check_dest(&ctl->unc, bucket);
+
+	if (!nc)
+		goto err_out_unlock;
+
+	netchannel_get(nc);
+	mutex_unlock(&bucket->mutex);
+
+	ret = nc->nc_read_data(nc, &ctl->timeout, &ctl->len, data);
+	
+	netchannel_put(nc);
+	return ret;
+
+err_out_unlock:
+	mutex_unlock(&bucket->mutex);
+	return ret;
+}
+
+static int netchannel_dump_info(struct unetchannel *unc)
+{
+	struct netchannel_cache_head *bucket;
+	struct netchannel *nc;
+	char *ncs = "none";
+	unsigned long hit = 0;
+	int err;
+	
+	bucket = netchannel_bucket(unc);
+
+	mutex_lock(&bucket->mutex);
+	nc = netchannel_check_full(unc, bucket);
+	if (!nc) {
+		nc = netchannel_check_dest(unc, bucket);
+		if (nc)
+			ncs = "dest";
+	} else 
+		ncs = "full";
+	if (nc)
+		hit = nc->hit;
+	mutex_unlock(&bucket->mutex);
+	err = (nc)?0:-ENODEV;
+
+	netchannel_dump_info_unc(unc, ncs, hit, err);
+
+	return err;
+}
+
+static int netchannel_connect(struct unetchannel *unc)
+{
+	struct netchannel *nc;
+	int err = -ENODEV;
+	struct netchannel_cache_head *bucket;
+	
+	bucket = netchannel_bucket(unc);
+	
+	mutex_lock(&bucket->mutex);
+	nc = netchannel_check_full(unc, bucket);
+	if (!nc)
+		goto err_out_unlock;
+	netchannel_get(nc);
+	mutex_unlock(&bucket->mutex);
+
+	err = 0;
+	if (nc->proto->connect)
+		err = nc->proto->connect(nc);
+	netchannel_put(nc);
+
+	return err;
+
+err_out_unlock:
+	mutex_unlock(&bucket->mutex);
+	return err;
+}
+
+asmlinkage long sys_netchannel_control(void __user *arg)
+{
+	struct unetchannel_control ctl;
+	int ret;
+
+	if (!netchannel_hash_table)
+		return -ENODEV;
+
+	if (copy_from_user(&ctl, arg, sizeof(struct unetchannel_control)))
+		return -ERESTARTSYS;
+
+	switch (ctl.cmd) {
+		case NETCHANNEL_CREATE:
+			ret = netchannel_create(&ctl.unc);
+			break;
+		case NETCHANNEL_CONNECT:
+			ret = netchannel_connect(&ctl.unc);
+			break;
+		case NETCHANNEL_BIND:
+			ret = netchannel_bind(&ctl);
+			break;
+		case NETCHANNEL_REMOVE:
+			ret = netchannel_remove(&ctl.unc);
+			break;
+		case NETCHANNEL_READ:
+			ret = netchannel_recv_data(&ctl, arg + sizeof(struct unetchannel_control));
+			break;
+		case NETCHANNEL_DUMP:
+			ret = netchannel_dump_info(&ctl.unc);
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+	}
+	
+	if (copy_to_user(arg, &ctl, sizeof(struct unetchannel_control)))
+		return -ERESTARTSYS;
+
+	return ret;
+}
+
+static inline void netchannel_dump_addr(struct in_ifaddr *ifa, char *str)
+{
+	printk(KERN_NOTICE "netchannel: %s %u.%u.%u.%u/%u.%u.%u.%u\n", str, NIPQUAD(ifa->ifa_local), NIPQUAD(ifa->ifa_mask));
+}
+
+static int netchannel_inetaddr_notifier_call(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct in_ifaddr *ifa = ptr;
+
+	switch (event) {
+		case NETDEV_UP:
+			netchannel_dump_addr(ifa, "add");
+			break;
+		case NETDEV_DOWN:
+			netchannel_dump_addr(ifa, "del");
+			break;
+		default:
+			netchannel_dump_addr(ifa, "unk");
+			break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+#ifdef CONFIG_IPV6
+static int netchannel_inet6addr_notifier_call(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct inet6_ifaddr *ifa = ptr;
+
+	printk(KERN_NOTICE "netchannel: inet6 event=%lx, ifa=%p.\n", event, ifa);
+	return NOTIFY_DONE;
+}
+#endif
+
+static int __init netchannel_init(void)
+{
+	unsigned int i, j, size;
+	int err = -ENOMEM;
+
+	size = (1 << netchannel_hash_order);
+
+	netchannel_hash_table = kzalloc(size * sizeof(void *), GFP_KERNEL);
+	if (!netchannel_hash_table)
+		goto err_out_exit;
+
+	for (i=0; i<size; ++i) {
+		struct netchannel_cache_head **col;
+
+		col = kzalloc(size * sizeof(void *), GFP_KERNEL);
+		if (!col)
+			break;
+		
+		for (j=0; j<size; ++j) {
+			struct netchannel_cache_head *head;
+
+			head = kzalloc(sizeof(struct netchannel_cache_head), GFP_KERNEL);
+			if (!head)
+				break;
+
+			INIT_HLIST_HEAD(&head->head);
+			mutex_init(&head->mutex);
+
+			col[j] = head;
+		}
+		
+		if (j<size && j>0) {
+			while (j >= 0)
+				kfree(col[j--]);
+			kfree(col);
+			break;
+		}
+
+		netchannel_hash_table[i] = col;
+	}
+
+	if (i<size) {
+		size = i;
+		goto err_out_free;
+	}
+
+	netchannel_cache = kmem_cache_create("netchannel", sizeof(struct netchannel), 0, 0,
+			NULL, NULL);
+	if (!netchannel_cache)
+		goto err_out_free;
+
+	register_inetaddr_notifier(&netchannel_inetaddr_notifier);
+#ifdef CONFIG_IPV6
+	register_inet6addr_notifier(&netchannel_inet6addr_notifier);
+#endif
+
+	printk(KERN_NOTICE "netchannel: Created %u order two-dimensional hash table.\n", 
+			netchannel_hash_order);
+
+	return 0;
+
+err_out_free:
+	for (i=0; i<size; ++i) {
+		for (j=0; j<(1 << netchannel_hash_order); ++j)
+			kfree(netchannel_hash_table[i][j]);
+		kfree(netchannel_hash_table[i]);
+	}
+	kfree(netchannel_hash_table);
+err_out_exit:
+	
+	printk(KERN_NOTICE "netchannel: Failed to create %u order two-dimensional hash table.\n", 
+			netchannel_hash_order);
+	return err;
+}
+
+static void __exit netchannel_exit(void)
+{
+	unsigned int i, j;
+
+	unregister_inetaddr_notifier(&netchannel_inetaddr_notifier);
+#ifdef CONFIG_IPV6
+	unregister_inet6addr_notifier(&netchannel_inet6addr_notifier);
+#endif
+	kmem_cache_destroy(netchannel_cache);
+
+	for (i=0; i<(1 << netchannel_hash_order); ++i) {
+		for (j=0; j<(1 << netchannel_hash_order); ++j)
+			kfree(netchannel_hash_table[i][j]);
+		kfree(netchannel_hash_table[i]);
+	}
+	kfree(netchannel_hash_table);
+}
+
+late_initcall(netchannel_init);
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index e40f753..6ea6379 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -428,6 +428,11 @@ config INET_TCP_DIAG
 	depends on INET_DIAG
 	def_tristate INET_DIAG
 
+config ATCP
+	bool "TCP: altenative TCP stack used for netchannels"
+	---help---
+	  Extremely lightweight RFC compliant TCP stack used for netchannels.
+
 config TCP_CONG_ADVANCED
 	bool "TCP: advanced congestion control"
 	---help---
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 9ef50a0..25c122f 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_TCP_CONG_HYBLA) += tcp_hybl
 obj-$(CONFIG_TCP_CONG_HTCP) += tcp_htcp.o
 obj-$(CONFIG_TCP_CONG_VEGAS) += tcp_vegas.o
 obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o
+obj-$(CONFIG_ATCP) += atcp.o
 
 obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
 		      xfrm4_output.o
diff --git a/net/ipv4/atcp.c b/net/ipv4/atcp.c
new file mode 100644
index 0000000..f8caece
--- /dev/null
+++ b/net/ipv4/atcp.c
@@ -0,0 +1,1434 @@
+/*
+ * 	tcp.c
+ * 
+ * 2006 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/random.h>
+#include <linux/netchannel.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+
+#include <net/tcp.h>
+#include <net/route.h>
+
+//#define ATCP_DEBUG
+
+#ifdef ATCP_DEBUG
+#define ulog(f, a...) printk(f, ##a)
+#else
+#define ulog(f, a...)
+#endif
+
+#if 0
+enum {
+	TCP_ESTABLISHED = 1,
+	TCP_SYN_SENT,
+	TCP_SYN_RECV,
+	TCP_FIN_WAIT1,
+	TCP_FIN_WAIT2,
+	TCP_TIME_WAIT,
+	TCP_CLOSE,
+	TCP_CLOSE_WAIT,
+	TCP_LAST_ACK,
+	TCP_LISTEN,
+	TCP_CLOSING
+};
+#endif
+
+#define packet_timestamp	(__u32)jiffies
+
+#define TCP_MAX_WSCALE	14
+static __u8 atcp_offer_wscale = 8;
+
+static __u32 atcp_max_qlen = 1024*10;
+
+struct atcp_protocol
+{
+	struct common_protocol	cproto;
+
+	struct netchannel	*nc;
+
+	__u32			state;
+
+	__u32			snd_una;
+	__u32			snd_nxt;
+	__u16			snd_wnd;
+	__u32			snd_wl1;
+	__u32			snd_wl2;
+	__u32			iss;
+
+	__u32			rcv_nxt;
+	__u16			rcv_wnd;
+	__u16			rcv_wup;
+	__u32			irs;
+
+	__u8			rwscale, swscale;
+	__u16			mss;
+	__u32			tsval, tsecr;
+	__u32			ack_sent, ack_missed;
+
+	struct sk_buff_head	ofo_queue;
+
+	struct sk_buff_head	retransmit_queue;
+	struct skb_timeval	first_packet_ts;
+	__u32			retransmit_timeout;
+
+	__u32			seq_read;
+
+	__u32			snd_cwnd, snd_ssthresh, in_flight, cong;
+
+	__u32			qlen;
+};
+
+struct state_machine
+{
+	__u32		state;
+	int		(*run)(struct atcp_protocol *, struct sk_buff *);
+};
+
+static inline struct atcp_protocol *atcp_convert(struct common_protocol *cproto)
+{
+	return (struct atcp_protocol *)cproto;
+}
+
+static inline __u32 skb_rwin(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	__u32 rwin = ntohs(skb->h.th->window);
+	return (rwin << tp->rwscale);
+}
+
+static inline __u32 tp_rwin(struct atcp_protocol *tp)
+{
+	__u32 rwin = tp->rcv_wnd;
+	return rwin << tp->rwscale;
+}
+
+static inline __u32 tp_swin(struct atcp_protocol *tp)
+{
+	__u32 swin = tp->snd_wnd;
+	return swin << tp->swscale;
+}
+
+static inline int beforeeq(__u32 seq1, __u32 seq2)
+{
+        return (__s32)(seq1-seq2) <= 0;
+}
+
+static inline int aftereq(__u32 seq1, __u32 seq2)
+{
+	return (__s32)(seq2-seq1) <= 0;
+}
+
+struct atcp_option
+{
+	__u8		kind, length;
+	int		(*callback)(struct atcp_protocol *tp, struct sk_buff *skb, __u8 *data);
+};
+
+struct atcp_option_timestamp
+{
+	__u8			kind, length;
+	__u32			tsval, tsecr;
+} __attribute__ ((packed));
+
+struct atcp_option_nop
+{
+	__u8			kind;
+} __attribute__ ((packed));
+
+struct atcp_option_mss
+{
+	__u8			kind, length;
+	__u16			mss;
+} __attribute__ ((packed));
+
+struct atcp_option_wscale
+{
+	__u8			kind, length;
+	__u8			wscale;
+} __attribute__ ((packed));
+
+#define TCP_OPT_NOP	1
+#define TCP_OPT_MSS	2
+#define TCP_OPT_WSCALE	3
+#define TCP_OPT_TS	8
+
+static int atcp_opt_mss(struct atcp_protocol *tp, struct sk_buff *skb __attribute__ ((unused)), __u8 *data)
+{
+	tp->mss = ntohs(((__u16 *)data)[0]);
+	ulog("%s: mss: %u.\n", __func__, tp->mss);
+	return 0;
+}
+
+static int atcp_opt_wscale(struct atcp_protocol *tp, struct sk_buff *skb __attribute__ ((unused)), __u8 *data)
+{
+	if ((skb->h.th->syn) && ((tp->state == TCP_SYN_SENT) || (tp->state == TCP_SYN_SENT))) {
+		tp->rwscale = data[0];
+		if (tp->rwscale > TCP_MAX_WSCALE)
+			tp->rwscale = TCP_MAX_WSCALE;
+		tp->swscale = atcp_offer_wscale;
+		ulog("%s: rwscale: %u, swscale: %u.\n", __func__, tp->rwscale, tp->swscale);
+	}
+	return 0;
+}
+
+static int atcp_opt_ts(struct atcp_protocol *tp, struct sk_buff *skb, __u8 *data)
+{
+	__u32 seq = TCP_SKB_CB(skb)->seq;
+	__u32 end_seq = TCP_SKB_CB(skb)->end_seq;
+	__u32 packet_tsval = ntohl(((__u32 *)data)[0]);
+
+	if (!skb->h.th->ack)
+		return 0;
+
+	/* PAWS check */
+	if ((tp->state == TCP_ESTABLISHED) && before(packet_tsval, tp->tsecr)) {
+		ulog("%s: PAWS failed: packet: seq: %u, end_seq: %u, tsval: %u, tsecr: %u, host tsval: %u, tsecr: %u.\n",
+				__func__, seq, end_seq, packet_tsval, ntohl(((__u32 *)data)[1]), tp->tsval, tp->tsecr);
+		return 1;
+	}
+	
+	if (between(tp->ack_sent, seq, end_seq))
+		tp->tsecr = packet_tsval;
+	return 0;
+}
+
+static struct atcp_option atcp_supported_options[] = {
+	[TCP_OPT_NOP] = {.kind = TCP_OPT_NOP, .length = 1},
+	[TCP_OPT_MSS] = {.kind = TCP_OPT_MSS, .length = 4, .callback = &atcp_opt_mss},
+	[TCP_OPT_WSCALE] = {.kind = TCP_OPT_WSCALE, .length = 3, .callback = &atcp_opt_wscale},
+	[TCP_OPT_TS] = {.kind = TCP_OPT_TS, .length = 10, .callback = &atcp_opt_ts},
+};
+
+#define TCP_FLAG_SYN	0x1
+#define TCP_FLAG_ACK	0x2
+#define TCP_FLAG_RST	0x4
+#define TCP_FLAG_PSH	0x8
+#define TCP_FLAG_FIN	0x10
+
+static inline void atcp_set_state(struct atcp_protocol *tp, __u32 state)
+{
+	ulog("state change: %u -> %u.\n", tp->state, state);
+	tp->state = state;
+}
+
+static int netchannel_ip_route_output_flow(struct rtable **rp, struct flowi *flp, int flags)
+{
+	int err;
+
+	err = __ip_route_output_key(rp, flp);
+	if (err)
+		return err;
+
+	if (flp->proto) {
+		if (!flp->fl4_src)
+			flp->fl4_src = (*rp)->rt_src;
+		if (!flp->fl4_dst)
+			flp->fl4_dst = (*rp)->rt_dst;
+	}
+
+	return 0;
+}
+
+struct dst_entry *netchannel_route_get_raw(struct netchannel *nc)
+{
+	struct rtable *rt;
+	struct flowi fl = { .oif = 0,
+			    .nl_u = { .ip4_u =
+				      { .daddr = nc->unc.faddr,
+					.saddr = nc->unc.laddr,
+					.tos = 0 } },
+			    .proto = nc->unc.proto,
+			    .uli_u = { .ports =
+				       { .sport = nc->unc.lport,
+					 .dport = nc->unc.fport } } };
+
+	if (netchannel_ip_route_output_flow(&rt, &fl, 0))
+		goto no_route;
+	return dst_clone(&rt->u.dst);
+
+no_route:
+	return NULL;
+}
+
+static inline struct dst_entry *netchannel_route_get(struct netchannel *nc)
+{
+	if (nc->dst && nc->dst->obsolete && nc->dst->ops->check(nc->dst, 0) == NULL) {
+		dst_release(nc->dst);
+		nc->dst = netchannel_route_get_raw(nc);
+		if (!nc->dst)
+			return NULL;
+	}
+	return dst_clone(nc->dst);
+}
+
+void netchannel_route_put(struct dst_entry *dst)
+{
+	/* dst_entry is being freed when skb is released in NIC */
+}
+
+static int transmit_data(struct sk_buff *skb, struct atcp_protocol *tp)
+{
+#ifdef ATCP_DEBUG
+	{
+		struct tcphdr *th = skb->h.th;
+
+		ulog("S %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u : seq: %u, ack: %u, win: %u [%u], doff: %u, "
+			"s: %u, a: %u, p: %u, r: %u, f: %u, len: %u, state: %u, skb: %p, csum: %04x.\n",
+			NIPQUAD(tp->nc->unc.laddr), ntohs(tp->nc->unc.lport),
+			NIPQUAD(tp->nc->unc.faddr), ntohs(tp->nc->unc.fport),
+			ntohl(th->seq), ntohl(th->ack_seq), ntohs(th->window), tp_rwin(tp), th->doff,
+			th->syn, th->ack, th->psh, th->rst, th->fin,
+			skb->len, tp->state, skb, th->check);
+	}
+#endif
+	return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
+}
+
+static int ip_build_header(struct netchannel *nc, struct sk_buff *skb)
+{
+	struct iphdr *iph;
+
+	skb->nh.iph = iph = (struct iphdr *)skb_push(skb, sizeof(struct iphdr));
+	if (!iph)
+		return -ENOMEM;
+
+	iph->saddr = nc->unc.laddr;
+	iph->daddr = nc->unc.faddr;
+	iph->tos = 0;
+	iph->tot_len = htons(skb->len);
+	iph->ttl = 64;
+	iph->id = 0;
+	iph->frag_off = htons(0x4000);
+	iph->version = 4;
+	iph->ihl = 5;
+	iph->protocol = nc->unc.proto;
+
+	ip_send_check(iph);
+
+	return 0;
+}
+
+static int atcp_build_header(struct atcp_protocol *tp, struct sk_buff *skb, __u32 flags, __u8 doff)
+{
+	struct tcphdr *th;
+	struct atcp_option_nop *nop;
+	struct atcp_option_timestamp *ts;
+
+	nop = (struct atcp_option_nop *)skb_push(skb, sizeof(struct atcp_option_nop));
+	nop->kind = 1;
+	nop = (struct atcp_option_nop *)skb_push(skb, sizeof(struct atcp_option_nop));
+	nop->kind = 1;
+
+	ts = (struct atcp_option_timestamp *)skb_push(skb, sizeof(struct atcp_option_timestamp));
+	ts->kind = atcp_supported_options[TCP_OPT_TS].kind;
+	ts->length = atcp_supported_options[TCP_OPT_TS].length;
+	ts->tsval = htonl(tp->tsval);
+	ts->tsecr = htonl(tp->tsecr);
+
+	skb->h.th = th = (struct tcphdr *)skb_push(skb, sizeof(struct tcphdr));
+	memset(th, 0, sizeof(struct tcphdr));
+
+	skb->dst = netchannel_route_get(tp->nc);
+	if (!skb->dst) {
+		ulog("%s: failed to get dst entry.\n", __func__);
+		return -ENODEV;
+	}
+#if 0
+	ulog("%s: len:%d head:%p data:%p tail:%p end:%p dev:%s\n",
+	       __func__, skb->len, skb->head, skb->data, skb->tail, skb->end,
+	       skb->dev ? skb->dev->name : "<NULL>");
+#endif
+	th->source = tp->nc->unc.lport;
+	th->dest = tp->nc->unc.fport;
+	th->seq = htonl(tp->snd_nxt);
+	th->ack_seq = htonl(tp->rcv_nxt);
+
+	if (flags & TCP_FLAG_SYN)
+		th->syn = 1;
+	if (flags & TCP_FLAG_ACK)
+		th->ack = 1;
+	if (flags & TCP_FLAG_PSH)
+		th->psh = 1;
+	if (flags & TCP_FLAG_RST)
+		th->rst = 1;
+	if (flags & TCP_FLAG_FIN)
+		th->fin = 1;
+	th->urg = 0;
+	th->urg_ptr = 0;
+	th->window = htons(tp->snd_wnd);
+	//th->window = 0xffff;
+
+	th->doff = 5 + 3 + doff;
+
+	skb->ip_summed = CHECKSUM_NONE;
+	skb->csum = 0;
+	th->check = tcp_v4_check(th, skb->len, tp->nc->unc.laddr, tp->nc->unc.faddr,
+			 csum_partial((char *)th, th->doff << 2, skb->csum));
+
+	TCP_SKB_CB(skb)->seq = tp->snd_nxt;
+	TCP_SKB_CB(skb)->end_seq = tp->snd_nxt + skb->len - (th->doff<<2);
+	TCP_SKB_CB(skb)->ack_seq = tp->rcv_nxt;
+
+	if (skb->len - (th->doff<<2))
+		tp->in_flight++;
+	tp->snd_nxt += th->syn + th->fin + skb->len - (th->doff<<2);
+	tp->ack_sent = tp->rcv_nxt;
+
+	return ip_build_header(tp->nc, skb);
+}
+
+static int atcp_send_data(struct atcp_protocol *tp, struct sk_buff *skb, __u32 flags, __u8 doff)
+{
+	int err;
+
+	err = atcp_build_header(tp, skb, flags, doff);
+	if (err)
+		return err;
+	return transmit_data(skb, tp);
+}
+
+static int atcp_send_bit(struct atcp_protocol *tp, __u32 flags)
+{
+	struct sk_buff *skb;
+	int err;
+
+	skb = alloc_skb(MAX_TCP_HEADER, GFP_KERNEL);
+	if (!skb) {
+		err = -ENOMEM;
+		goto err_out_exit;
+	}
+
+	skb->dst = netchannel_route_get(tp->nc);
+	if (!skb->dst) {
+		err = -ENODEV;
+		goto err_out_free;
+	}
+
+	skb_reserve(skb, MAX_TCP_HEADER);
+
+	err = atcp_send_data(tp, skb, flags, 0);
+	if (err < 0)
+		goto err_out_put;
+	netchannel_route_put(skb->dst);
+
+	return 0;
+
+err_out_put:
+	netchannel_route_put(skb->dst);
+err_out_free:
+	kfree_skb(skb);
+err_out_exit:
+	return err;
+}
+
+static int atcp_listen(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	int err;
+	struct tcphdr *th = skb->h.th;
+
+	if (th->rst)
+		return 0;
+	if (th->ack)
+		return -1;
+
+	if (th->syn) {
+		tp->irs = ntohl(th->seq);
+		tp->rcv_nxt = ntohl(th->seq)+1;
+		get_random_bytes(&tp->iss, sizeof(tp->iss));
+
+		err = atcp_send_bit(tp, TCP_FLAG_SYN|TCP_FLAG_ACK);
+		if (err < 0)
+			return err;
+		atcp_set_state(tp, TCP_SYN_RECV);
+	}
+
+	return 0;
+}
+
+static void atcp_cleanup_queue(struct sk_buff_head *head, __u32 *qlen)
+{
+	struct sk_buff *skb, *n = skb_peek(head);
+
+	if (!n)
+		return;
+
+	do {
+		skb = n->next;
+		skb_unlink(n, head);
+		if (qlen)
+			*qlen -= n->len;
+		kfree_skb(n);
+		n = skb;
+	} while (n != (struct sk_buff *)head);
+}
+
+static void atcp_check_retransmit_queue(struct atcp_protocol *tp, __u32 ack)
+{
+	struct sk_buff *skb, *n = skb_peek(&tp->retransmit_queue);
+	int removed = 0;
+
+	if (!n)
+		goto out;
+
+	do {
+		__u32 seq, end_seq;
+
+		/*
+		 * If this header is not setup, then packet was not sent at all yet,
+		 * so it can not be acked.
+		 */
+		if (!n->h.raw)
+			break;
+
+		seq = TCP_SKB_CB(n)->seq;
+		end_seq = TCP_SKB_CB(n)->end_seq;
+
+		if (after(end_seq, ack))
+			break;
+		else {
+			tp->in_flight--;
+			ulog("%s: ack: %u, snd_una: %u, removing: seq: %u, end_seq: %u, ts: %u.%u, in_flight: %u.\n", 
+					__func__, ack, tp->snd_una, seq, end_seq, n->tstamp.off_sec, n->tstamp.off_usec, tp->in_flight);
+			skb = n->next;
+			skb_unlink(n, &tp->retransmit_queue);
+			tp->qlen -= n->len;
+			kfree_skb(n);
+			n = skb;
+			removed++;
+
+			if (n != (struct sk_buff *)&tp->retransmit_queue)
+				tp->first_packet_ts = n->tstamp;
+		}
+	} while (n != (struct sk_buff *)&tp->retransmit_queue);
+out:
+	ulog("%s: removed: %d, in_flight: %u, cwnd: %u.\n", __func__, removed, tp->in_flight, tp->snd_cwnd);
+}
+
+static inline int atcp_retransmit_time(struct atcp_protocol *tp)
+{
+	return (after(packet_timestamp, tp->first_packet_ts.off_sec + tp->retransmit_timeout));
+}
+
+static void atcp_retransmit(struct atcp_protocol *tp)
+{
+	struct sk_buff *skb = skb_peek(&tp->retransmit_queue);
+	int retransmitted = 0;
+
+	if (tp->state == TCP_CLOSE) {
+		atcp_cleanup_queue(&tp->retransmit_queue, &tp->qlen);
+		return;
+	}
+
+	if (!skb)
+		goto out;
+
+	do {
+		if (after(packet_timestamp, skb->tstamp.off_sec + tp->retransmit_timeout)) {
+			int err;
+#ifdef ATCP_DEBUG
+			{
+				__u32 seq = TCP_SKB_CB(skb)->seq;
+				__u32 end_seq = TCP_SKB_CB(skb)->end_seq;
+
+				ulog("%s: skb: %p, seq: %u, end_seq: %u, ts: %u.%u, time: %u.\n", 
+					__func__, skb, seq, end_seq, skb->tstamp.off_sec, skb->tstamp.off_usec, packet_timestamp);
+			}
+#endif
+			skb_get(skb);
+			err = transmit_data(skb, tp);
+			if (err)
+				kfree_skb(skb);
+			retransmitted++;
+		} else
+			break;
+	} while ((skb = skb->next) != (struct sk_buff *)&tp->retransmit_queue);
+out:
+	return;
+	//ulog("%s: retransmitted: %d.\n", __func__, retransmitted);
+}
+
+static void skb_queue_order(struct sk_buff *skb, struct sk_buff_head *head)
+{
+	struct sk_buff *next = skb_peek(head);
+	unsigned int nseq = TCP_SKB_CB(skb)->seq;
+	unsigned int nend_seq = TCP_SKB_CB(skb)->end_seq;
+
+	ulog("ofo queue: seq: %u, end_seq: %u.\n", nseq, nend_seq);
+
+	if (!next) {
+		skb_get(skb);
+		__skb_queue_tail(head, skb);
+		goto out;
+	}
+
+	do {
+		unsigned int seq = TCP_SKB_CB(next)->seq;
+		unsigned int end_seq = TCP_SKB_CB(next)->end_seq;
+
+		if (beforeeq(seq, nseq) && aftereq(end_seq, nend_seq)) {
+			ulog("Collapse 1: seq: %u, end_seq: %u removed by seq: %u, end_seq: %u.\n",
+					nseq, nend_seq, seq, end_seq);
+			kfree_skb(skb);
+			skb = NULL;
+			break;
+		}
+
+		if (beforeeq(nseq, seq) && aftereq(nend_seq, end_seq)) {
+			struct sk_buff *prev = next->prev;
+
+			skb_unlink(next, head);
+
+			ulog("Collapse 2: seq: %u, end_seq: %u removed by seq: %u, end_seq: %u.\n",
+					seq, end_seq, nseq, nend_seq);
+
+			kfree_skb(next);
+			if (prev == (struct sk_buff *)head)
+				break;
+			next = prev;
+			seq = TCP_SKB_CB(next)->seq;
+			end_seq = TCP_SKB_CB(next)->end_seq;
+		}
+		if (after(seq, nseq))
+			break;
+	} while ((next = next->next) != (struct sk_buff *)head);
+
+	if (skb) {
+		ulog("Inserting seq: %u, end_seq: %u.\n", nseq, nend_seq);
+		skb_get(skb);
+		skb_insert(next, skb, head);
+	}
+out:
+	ulog("ofo dump: ");
+	next = (struct sk_buff *)head;
+	while ((next = next->next) != (struct sk_buff *)head) {
+		ulog("%u - %u, ", TCP_SKB_CB(next)->seq, TCP_SKB_CB(next)->end_seq);
+	}
+	ulog("\n");
+}
+
+static void skb_queue_check(struct atcp_protocol *tp, struct sk_buff_head *head)
+{
+	struct sk_buff *next = skb_peek(head);
+
+	if (!next)
+		return;
+
+	do {
+		unsigned int seq = TCP_SKB_CB(next)->seq;
+		unsigned int end_seq = TCP_SKB_CB(next)->end_seq;
+
+		if (before(tp->rcv_nxt, seq))
+			break;
+
+		tp->rcv_nxt = max_t(unsigned int, end_seq, tp->rcv_nxt);
+	} while ((next = next->next) != (struct sk_buff *)head);
+
+	ulog("ACKed: rcv_nxt: %u.\n", tp->rcv_nxt);
+}
+
+static int atcp_syn_sent(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	struct tcphdr *th = skb->h.th;
+	__u32 seq = htonl(th->seq);
+	__u32 ack = htonl(th->ack_seq);
+#if 0
+	ulog("%s: a: %d, s: %d, ack: %u, seq: %u, iss: %u, snd_nxt: %u, snd_una: %u.\n",
+			__func__, th->ack, th->syn, ack, seq, tp->iss, tp->snd_nxt, tp->snd_una);
+#endif
+	if (th->ack) {
+		if (beforeeq(ack, tp->iss) || after(ack, tp->snd_nxt))
+			return (th->rst)?0:-1;
+		if (between(ack, tp->snd_una, tp->snd_nxt)) {
+			if (th->rst) {
+				atcp_set_state(tp, TCP_CLOSE);
+				return 0;
+			}
+		}
+	}
+
+	if (th->rst)
+		return 0;
+
+	if (th->syn) {
+		tp->rcv_nxt = seq+1;
+		tp->irs = seq;
+		if (th->ack) {
+			tp->snd_una = ack;
+			atcp_check_retransmit_queue(tp, ack);
+		}
+
+		if (after(tp->snd_una, tp->iss)) {
+			atcp_set_state(tp, TCP_ESTABLISHED);
+			tp->seq_read = seq + 1;
+			return atcp_send_bit(tp, TCP_FLAG_ACK);
+		}
+
+		atcp_set_state(tp, TCP_SYN_RECV);
+		tp->snd_nxt = tp->iss;
+		return atcp_send_bit(tp, TCP_FLAG_ACK|TCP_FLAG_SYN);
+	}
+
+	return 0;
+}
+
+static int atcp_syn_recv(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	struct tcphdr *th = skb->h.th;
+	__u32 ack = ntohl(th->ack_seq);
+
+	if (th->rst) {
+		atcp_set_state(tp, TCP_CLOSE);
+		return 0;
+	}
+
+	if (th->ack) {
+		if (between(ack, tp->snd_una, tp->snd_nxt)) {
+			tp->seq_read = ntohl(th->seq) + 1;
+			atcp_set_state(tp, TCP_ESTABLISHED);
+			return 0;
+		}
+	}
+
+	if (th->fin) {
+		atcp_set_state(tp, TCP_CLOSE_WAIT);
+		return 0;
+	}
+
+	return -1;
+}
+
+static void atcp_process_ack(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	__u32 ack = TCP_SKB_CB(skb)->ack_seq;
+	struct sk_buff *n = skb_peek(&tp->retransmit_queue);
+
+	if (!n)
+		return;
+
+	do {
+		__u32 ret_end_seq;
+
+		if (!n->h.raw)
+			break;
+		
+		ret_end_seq = TCP_SKB_CB(n)->end_seq;
+		skb = n->next;
+
+		if (before(ret_end_seq, ack)) {
+			skb_unlink(n, &tp->retransmit_queue);
+			kfree_skb(n);
+		}
+		n = skb;
+	} while (n != (struct sk_buff *)&tp->retransmit_queue);
+}
+
+static int atcp_in_slow_start(struct atcp_protocol *tp)
+{
+	return tp->snd_cwnd * tp->mss <= tp->snd_ssthresh;
+}
+
+static void atcp_congestion(struct atcp_protocol *tp)
+{
+	__u32 min_wind = min_t(unsigned int, tp->snd_cwnd*tp->mss, tp_rwin(tp));
+	tp->snd_ssthresh = max_t(unsigned int, tp->mss * 2, min_wind/2);
+	if (tp->snd_cwnd == 1)
+		return;
+	tp->snd_cwnd >>= 1;
+	tp->cong++;
+}
+
+static int atcp_established(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	struct tcphdr *th = skb->h.th;
+	int err = -EINVAL;
+	__u32 seq = TCP_SKB_CB(skb)->seq;
+	__u32 end_seq = TCP_SKB_CB(skb)->end_seq;
+	__u32 ack = TCP_SKB_CB(skb)->ack_seq;
+	__u32 rwin = tp_rwin(tp);
+
+	if (before(seq, tp->rcv_nxt)) {
+		err = 0;
+		goto out;
+	}
+
+	if (after(end_seq, tp->rcv_nxt + rwin)) {
+		ulog("%s: 1: seq: %u, size: %u, rcv_nxt: %u, rcv_wnd: %u.\n", 
+				__func__, seq, skb->len, tp->rcv_nxt, rwin);
+		goto out;
+	}
+
+	if (th->rst)
+		goto out;
+
+	ulog("%s: seq: %u, end_seq: %u, ack: %u, snd_una: %u, snd_nxt: %u, snd_wnd: %u, rcv_nxt: %u, rcv_wnd: %u, cwnd: %u.\n",
+			__func__, seq, end_seq, ack, 
+			tp->snd_una, tp->snd_nxt, tp_swin(tp), 
+			tp->rcv_nxt, rwin, tp->snd_cwnd);
+
+	if (between(ack, tp->snd_una, tp->snd_nxt)) {
+		tp->snd_cwnd++;
+		tp->snd_una = ack;
+		atcp_check_retransmit_queue(tp, ack);
+	} else if (before(ack, tp->snd_una)) {
+		ulog("%s: duplicate 3 ack: %u, snd_una: %u, snd_nxt: %u, snd_wnd: %u, snd_wl1: %u, snd_wl2: %u.\n",
+				__func__, ack, tp->snd_una, tp->snd_nxt, tp_swin(tp), tp->snd_wl1, tp->snd_wl2);
+		atcp_congestion(tp);
+		atcp_check_retransmit_queue(tp, ack);
+		return 0;
+	} else if (after(ack, tp->snd_nxt)) {
+		err = atcp_send_bit(tp, TCP_FLAG_ACK);
+		if (err < 0)
+			goto out;
+	}
+
+	if (beforeeq(seq, tp->rcv_nxt) && aftereq(end_seq, tp->rcv_nxt)) {
+		tp->rcv_nxt = end_seq;
+		skb_queue_check(tp, &tp->ofo_queue);
+	} else {
+		/*
+		 * Out of order packet.
+		 */
+		err = 0;
+		goto out;
+	}
+
+	if (!skb->len) {
+		atcp_process_ack(tp, skb);
+	} else {
+		skb_queue_order(skb, &tp->ofo_queue);
+
+		if (atcp_in_slow_start(tp) || ++tp->ack_missed >= 3) {
+			tp->ack_missed = 0;
+			err = atcp_send_bit(tp, TCP_FLAG_ACK);
+			if (err < 0)
+				goto out;
+		}
+	}
+
+	if (before(tp->snd_wl1, seq) || ((tp->snd_wl1 == seq) && beforeeq(tp->snd_wl2, ack))) {
+		tp->snd_wnd = ntohs(th->window);
+		tp->snd_wl1 = seq;
+		tp->snd_wl2 = ack;
+	}
+
+	if (th->fin) {
+		atcp_set_state(tp, TCP_CLOSE_WAIT);
+		err = 0;
+	}
+
+	err = skb->len;
+out:
+	ulog("%s: return: %d.\n", __func__, err);
+	return err;
+}
+
+static int atcp_fin_wait1(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	int err;
+	struct tcphdr *th = skb->h.th;
+
+	if (th->fin) {
+		if (th->ack) {
+			/* Start time-wait timer... */
+			atcp_set_state(tp, TCP_TIME_WAIT);
+		} else
+			atcp_set_state(tp, TCP_CLOSING);
+		return 0;
+	}
+
+	err = atcp_established(tp, skb);
+	if (err < 0)
+		return err;
+	atcp_set_state(tp, TCP_FIN_WAIT2);
+	return 0;
+}
+
+static int atcp_fin_wait2(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	struct tcphdr *th = skb->h.th;
+
+	if (th->fin) {
+		/* Start time-wait timer... */
+		return 0;
+	}
+
+	return atcp_established(tp, skb);
+}
+
+static int atcp_close_wait(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	struct tcphdr *th = skb->h.th;
+
+	if (th->fin)
+		return 0;
+
+	return atcp_established(tp, skb);
+}
+
+static int atcp_closing(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	int err;
+	struct tcphdr *th = skb->h.th;
+
+	if (th->fin)
+		return 0;
+
+	err = atcp_established(tp, skb);
+	if (err < 0)
+		return err;
+	atcp_set_state(tp, TCP_TIME_WAIT);
+	return 0;
+}
+
+static int atcp_last_ack(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	struct tcphdr *th = skb->h.th;
+
+	if (th->fin)
+		return 0;
+
+	atcp_set_state(tp, TCP_CLOSE);
+	return 0;
+}
+
+static int atcp_time_wait(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	return atcp_send_bit(tp, TCP_FLAG_ACK);
+}
+
+static int atcp_close(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	struct tcphdr *th = skb->h.th;
+
+	atcp_cleanup_queue(&tp->retransmit_queue, &tp->qlen);
+	atcp_cleanup_queue(&tp->ofo_queue, NULL);
+
+	if (!th->rst)
+		return -1;
+	return 0;
+}
+
+static struct state_machine atcp_state_machine[] = {
+	{ .state = 0, .run = NULL},
+	{ .state = TCP_ESTABLISHED, .run = atcp_established, },
+	{ .state = TCP_SYN_SENT, .run = atcp_syn_sent, },
+	{ .state = TCP_SYN_RECV, .run = atcp_syn_recv, },
+	{ .state = TCP_FIN_WAIT1, .run = atcp_fin_wait1, },
+	{ .state = TCP_FIN_WAIT2, .run = atcp_fin_wait2, },
+	{ .state = TCP_TIME_WAIT, .run = atcp_time_wait, },
+	{ .state = TCP_CLOSE, .run = atcp_close, },
+	{ .state = TCP_CLOSE_WAIT, .run = atcp_close_wait, },
+	{ .state = TCP_LAST_ACK, .run = atcp_last_ack, },
+	{ .state = TCP_LISTEN, .run = atcp_listen, },
+	{ .state = TCP_CLOSING, .run = atcp_closing, },
+};
+
+static int atcp_connect(struct netchannel *nc)
+{
+	struct atcp_protocol *tp = atcp_convert(nc->proto);
+	int err;
+	struct sk_buff *skb;
+	struct atcp_option_mss *mss;
+	struct atcp_option_wscale *wscale;
+	struct atcp_option_nop *nop;
+
+	get_random_bytes(&tp->iss, sizeof(tp->iss));
+	tp->snd_wnd = 4096;
+	tp->snd_nxt = tp->iss;
+	tp->rcv_wnd = 0xffff;
+	tp->rwscale = 0;
+	tp->swscale = 0;
+	tp->snd_cwnd = 1;
+	tp->mss = 1460;
+	tp->snd_ssthresh = 0xffff;
+	tp->retransmit_timeout = 10;
+	tp->tsval = packet_timestamp;
+	tp->tsecr = 0;
+	tp->nc = nc;
+	skb_queue_head_init(&tp->retransmit_queue);
+	skb_queue_head_init(&tp->ofo_queue);
+
+	skb = alloc_skb(MAX_TCP_HEADER, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	skb_reserve(skb, MAX_TCP_HEADER);
+
+	mss = (struct atcp_option_mss *)skb_push(skb, sizeof(struct atcp_option_mss));
+	mss->kind = TCP_OPT_MSS;
+	mss->length = atcp_supported_options[TCP_OPT_MSS].length;
+	mss->mss = htons(tp->mss);
+
+	nop = (struct atcp_option_nop *)skb_push(skb, sizeof(struct atcp_option_nop));
+	nop->kind = 1;
+	
+	wscale = (struct atcp_option_wscale *)skb_push(skb, sizeof(struct atcp_option_wscale));
+	wscale->kind = TCP_OPT_WSCALE;
+	wscale->length = atcp_supported_options[TCP_OPT_WSCALE].length;
+	wscale->wscale = atcp_offer_wscale;
+
+	err = atcp_send_data(tp, skb, TCP_FLAG_SYN, skb->len/4);
+	if (err < 0)
+		goto err_out_free;
+
+	atcp_set_state(tp, TCP_SYN_SENT);
+	return 0;
+
+err_out_free:
+	kfree_skb(skb);
+	return err;
+}
+
+static int atcp_parse_options(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	struct tcphdr *th = skb->h.th;
+	int optsize = (th->doff<<2) - sizeof(struct tcphdr);
+	__u8 *opt = (__u8 *)skb->h.raw + sizeof(struct tcphdr);
+	int err = 0;
+
+	if (optsize < 0)
+		return -EINVAL;
+
+	while (optsize) {
+		__u8 kind = *opt++;
+		__u8 len; 
+
+		if (kind == 1) {
+			optsize--;
+			continue;
+		} else if (kind == 0)
+			break;
+		else
+			len = *opt++;
+
+		//ulog("%s: kind: %u, len: %u, optsize: %d.\n", __func__, kind, len, optsize);
+
+		if (kind < sizeof(atcp_supported_options)/sizeof(atcp_supported_options[0])) {
+			if (optsize < len) {
+				err = -EINVAL;
+				break;
+			}
+			if (atcp_supported_options[kind].callback) {
+				err = atcp_supported_options[kind].callback(tp, skb, opt);
+				if (err)
+					break;
+			}
+		}
+		opt += len - 2;
+		optsize -= len;
+	}
+	return err;
+}
+
+static int atcp_state_machine_run(struct atcp_protocol *tp, struct sk_buff *skb)
+{
+	int err = -EINVAL, broken = 1;
+	struct tcphdr *th = skb->h.th;
+	__u16 rwin = skb_rwin(tp, skb);
+	__u32 seq = TCP_SKB_CB(skb)->seq;
+	__u32 ack = TCP_SKB_CB(skb)->ack_seq;
+
+	ulog("R %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u : seq: %u, ack: %u, win: %u [%u], doff: %u, "
+			"s: %u, a: %u, p: %u, r: %u, f: %u, len: %u, state: %u, skb: %p.\n",
+		NIPQUAD(tp->nc->unc.laddr), ntohs(tp->nc->unc.lport),
+		NIPQUAD(tp->nc->unc.faddr), ntohs(tp->nc->unc.fport),
+		seq, ack, ntohs(th->window), rwin, th->doff,
+		th->syn, th->ack, th->psh, th->rst, th->fin,
+		skb->len, tp->state, skb);
+
+	tp->rcv_wnd = ntohs(th->window);
+
+	/* Some kind of header prediction. */
+	if ((tp->state == TCP_ESTABLISHED) && (seq == tp->rcv_nxt)) {
+		int sz;
+
+		err = atcp_established(tp, skb);
+		if (err < 0)
+			goto out;
+		sz = err;
+		err = atcp_parse_options(tp, skb);
+		if (err >= 0)
+			err = sz;
+		goto out;
+	}
+
+	err = atcp_parse_options(tp, skb);
+	if (err < 0)
+		goto out;
+	if (err > 0)
+		return atcp_send_bit(tp, TCP_FLAG_ACK);
+
+	if (tp->state == TCP_SYN_SENT) {
+		err = atcp_state_machine[tp->state].run(tp, skb);
+	} else {
+		if (!skb->len && ((!rwin && seq == tp->rcv_nxt) || 
+					(rwin && (aftereq(seq, tp->rcv_nxt) && before(seq, tp->rcv_nxt + rwin)))))
+				broken = 0;
+		else if ((aftereq(seq, tp->rcv_nxt) && before(seq, tp->rcv_nxt + rwin)) &&
+					(aftereq(seq, tp->rcv_nxt) && before(seq+skb->len-1, tp->rcv_nxt + rwin)))
+				broken = 0;
+
+		if (broken && !th->rst) {
+			ulog("R broken: rwin: %u, seq: %u, rcv_nxt: %u, size: %u.\n", 
+					rwin, seq, tp->rcv_nxt, skb->len);
+			return atcp_send_bit(tp, TCP_FLAG_ACK);
+		}
+
+		if (th->rst) {
+			ulog("R broken rst: rwin: %u, seq: %u, rcv_nxt: %u, size: %u.\n", 
+					rwin, seq, tp->rcv_nxt, skb->len);
+			atcp_set_state(tp, TCP_CLOSE);
+			err = 0;
+			goto out;
+		}
+
+		if (th->syn) {
+			ulog("R broken syn: rwin: %u, seq: %u, rcv_nxt: %u, size: %u.\n", 
+					rwin, seq, tp->rcv_nxt, skb->len);
+			goto out;
+		}
+
+		if (!th->ack)
+			goto out;
+
+		err = atcp_state_machine[tp->state].run(tp, skb);
+
+		if (between(ack, tp->snd_una, tp->snd_nxt)) {
+			tp->snd_una = ack;
+			atcp_check_retransmit_queue(tp, ack);
+		}
+
+		if (th->fin && seq == tp->rcv_nxt) {
+			if (tp->state == TCP_LISTEN || tp->state == TCP_CLOSE)
+				return 0;
+			tp->rcv_nxt++;
+			atcp_send_bit(tp, TCP_FLAG_ACK);
+		}
+	}
+
+out:
+#if 0
+	ulog("E %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u : seq: %u, ack: %u, state: %u, err: %d.\n",
+		NIPQUAD(tp->nc->unc.laddr), ntohs(tp->nc->unc.lport),
+		NIPQUAD(tp->nc->unc.faddr), ntohs(tp->nc->unc.fport),
+		ntohl(th->seq), ntohl(th->ack_seq), tp->state, err);
+#endif
+	if (err < 0) {
+		__u32 flags = TCP_FLAG_RST;
+		if (th->ack) {
+			tp->snd_nxt = ntohl(th->ack_seq);
+		} else {
+			flags |= TCP_FLAG_ACK;
+			tp->snd_nxt = 0;
+			tp->rcv_nxt = ntohl(th->seq) + skb->len;
+		}
+		atcp_set_state(tp, TCP_CLOSE);
+		atcp_send_bit(tp, flags);
+		atcp_cleanup_queue(&tp->retransmit_queue, &tp->qlen);
+	}
+
+	if (atcp_retransmit_time(tp))
+		atcp_retransmit(tp);
+
+	return err;
+}
+
+static int atcp_read_data(struct atcp_protocol *tp, __u8 *buf, unsigned int size)
+{
+	struct sk_buff *skb = skb_peek(&tp->ofo_queue);
+	int read = 0;
+
+	if (!skb)
+		return -EAGAIN;
+
+	ulog("%s: size: %u, seq_read: %u.\n", __func__, size, tp->seq_read);
+
+	while (size && (skb != (struct sk_buff *)&tp->ofo_queue)) {
+		__u32 seq = TCP_SKB_CB(skb)->seq;
+		__u32 end_seq = TCP_SKB_CB(skb)->end_seq;
+		unsigned int sz, data_size, off, len;
+		struct sk_buff *next = skb->next;
+
+		if (after(tp->seq_read, end_seq)) {
+			ulog("Impossible: skb: seq: %u, end_seq: %u, seq_read: %u.\n",
+					seq, end_seq, tp->seq_read);
+
+			skb_unlink(skb, &tp->ofo_queue);
+			kfree_skb(skb);
+
+			skb = next;
+			continue;
+		}
+
+		if (before(tp->seq_read, seq))
+			break;
+
+		off = tp->seq_read - seq;
+		data_size = skb->len - off;
+		sz = min_t(unsigned int, size, data_size);
+
+		ulog("Copy: seq_read: %u, seq: %u, end_seq: %u, size: %u, off: %u, data_size: %u, sz: %u, read: %d.\n",
+				tp->seq_read, seq, end_seq, size, off, data_size, sz, read);
+
+		len = sz;
+		while (len) {
+			unsigned int copied = sz - len;
+			
+			len = copy_to_user(&buf[copied], skb->data + off + copied, len);
+		}
+
+		buf += sz;
+		read += sz;
+
+		tp->seq_read += sz;
+
+		if (aftereq(tp->seq_read, end_seq)) {
+			ulog("Unlinking: skb: seq: %u, end_seq: %u, seq_read: %u.\n",
+					seq, end_seq, tp->seq_read);
+
+			skb_unlink(skb, &tp->ofo_queue);
+			kfree_skb(skb);
+		}
+
+		skb = next;
+	}
+
+	return read;
+}
+
+static int atcp_process_in(struct netchannel *nc, void *buf, unsigned int size)
+{
+	struct atcp_protocol *tp = atcp_convert(nc->proto);
+	struct tcphdr *th;
+	struct iphdr *iph;
+	struct sk_buff *skb;
+	int err = 0;
+	unsigned int read = 0, timeout = HZ;
+
+	while (size) {
+		unsigned int tm = timeout, len;
+#if 0
+		if (skb_queue_empty(&nc->recv_queue) && read)
+			break;
+#endif
+		skb = netchannel_get_skb(nc, &tm, &err);
+		if (!skb) 
+			break;
+
+		iph = skb->nh.iph;
+		th = skb->h.th;
+
+		skb_pull(skb, (th->doff<<2) + (iph->ihl<<2));
+		len = skb->len;
+
+		ulog("\n%s: skb: %p, data_size: %u.\n", __func__, skb, skb->len);
+
+		TCP_SKB_CB(skb)->seq = ntohl(th->seq);
+		TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + skb->len;
+		TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
+
+		err = atcp_state_machine_run(tp, skb);
+		if (err <= 0) {
+			kfree_skb(skb);
+			break;
+		}
+
+		if (len) {
+			err = atcp_read_data(tp, buf, size);
+
+			if (err > 0) {
+				size -= err;
+				buf += err;
+				read += err;
+			}
+		}
+
+		kfree_skb(skb);
+	}
+
+	if (atcp_retransmit_time(tp))
+		atcp_retransmit(tp);
+
+	return read;
+}
+
+static int atcp_can_send(struct atcp_protocol *tp)
+{
+	__u32 can_send = tp->snd_cwnd > tp->in_flight;
+
+	ulog("%s: swin: %u, rwin: %u, cwnd: %u, in_flight: %u, ssthresh: %u, qlen: %u, ss: %d.\n", 
+			__func__, tp_swin(tp), tp_rwin(tp), tp->snd_cwnd, tp->in_flight, tp->snd_ssthresh, 
+			tp->qlen, atcp_in_slow_start(tp));
+	return can_send;
+}
+
+static int atcp_transmit_combined(struct netchannel *nc, void *buf, unsigned int data_size)
+{
+	struct atcp_protocol *tp = atcp_convert(nc->proto);
+	struct sk_buff *skb;
+	struct dst_entry *dst;
+	int err = 0;
+	unsigned int copy, total = 0;
+	
+	dst = netchannel_route_get(nc);
+	if (!dst) {
+		err = -ENODEV;
+		goto out_exit;
+	}
+
+	while (data_size) {
+		skb = skb_peek_tail(&tp->retransmit_queue);
+		if (!skb || !skb_tailroom(skb)) {
+			skb = alloc_skb(tp->mss, GFP_KERNEL);
+			if (!skb) {
+				err = -ENOMEM;
+				goto out;
+			}
+
+			skb->dst = dst;
+			skb_reserve(skb, MAX_TCP_HEADER);
+			
+			skb_get(skb);
+			__skb_queue_tail(&tp->retransmit_queue, skb);
+			tp->qlen += skb_tailroom(skb);
+			ulog("%s: queued skb: %p, size: %u, tail_len: %u.\n", __func__, skb, skb->len, skb_tailroom(skb));
+		} 
+
+		copy = min_t(unsigned int, skb_tailroom(skb), data_size);
+		memcpy(skb_put(skb, copy), buf, copy);
+		skb->tail += copy;
+		skb->len += copy;
+		buf += copy;
+		data_size -= copy;
+		total += copy;
+		
+		ulog("%s: skb: %p, copy: %u, total: %u, data_size: %u, skb_size: %u, tail_len: %u.\n", 
+				__func__, skb, copy, total, data_size, skb->len, skb_tailroom(skb));
+		if (!skb_tailroom(skb)) {
+			err = atcp_send_data(tp, skb, TCP_FLAG_PSH|TCP_FLAG_ACK, 0);
+			if (err)
+				goto out;
+		}
+	}
+	err = total;
+
+out:
+	netchannel_route_put(dst);
+out_exit:
+	return err;
+}
+
+static int atcp_transmit_data(struct netchannel *nc, void *buf, unsigned int data_size)
+{
+	struct atcp_protocol *tp = atcp_convert(nc->proto);
+	struct sk_buff *skb;
+	unsigned int size;
+	struct dst_entry *dst;
+	int err;
+
+	dst = netchannel_route_get(nc);
+	if (!dst) {
+		err = -ENODEV;
+		goto err_out_exit;
+	}
+
+	if (atcp_in_slow_start(tp) || data_size + MAX_TCP_HEADER > tp->mss)
+		size = data_size + MAX_TCP_HEADER;
+	else
+		size = tp->mss;
+	
+	skb = alloc_skb(size, GFP_KERNEL);
+	if (!skb) {
+		err = -ENOMEM;
+		dst_release(dst);
+		goto err_out_put;
+	}
+
+	skb->dst = dst;
+	skb_reserve(skb, MAX_TCP_HEADER);
+
+	memcpy(skb_put(skb, data_size), buf, data_size);
+
+	skb_get(skb);
+	__skb_queue_tail(&tp->retransmit_queue, skb);
+	tp->qlen += skb->len;
+	ulog("%s: queued: skb: %p, size: %u, qlen: %u.\n", __func__, skb, skb->len, tp->qlen);
+
+	err = atcp_send_data(tp, skb, TCP_FLAG_PSH|TCP_FLAG_ACK, 0);
+	if (err)
+		goto err_out_free;
+	
+	netchannel_route_put(dst);
+
+	return data_size;
+
+err_out_free:
+	kfree_skb(skb);
+err_out_put:
+	netchannel_route_put(dst);
+err_out_exit:
+	return err;
+}
+
+static int atcp_process_out(struct netchannel *nc, void *buf, unsigned int data_size)
+{
+	struct atcp_protocol *tp = atcp_convert(nc->proto);
+
+	if (tp->state != TCP_ESTABLISHED)
+		return -1;
+#if 0
+	if (tp->qlen + data_size > atcp_max_qlen)
+		return -ENOMEM;
+#endif	
+
+	if (!atcp_can_send(tp))
+		return -EAGAIN;
+
+	if (atcp_in_slow_start(tp) || data_size + MAX_TCP_HEADER > tp->mss)
+		return atcp_transmit_data(nc, buf, data_size);
+		
+	return atcp_transmit_combined(nc, buf, data_size);
+}
+
+static int atcp_destroy(struct netchannel *nc)
+{
+	struct atcp_protocol *tp = atcp_convert(nc->proto);
+
+	if (tp->state == TCP_SYN_RECV ||
+			tp->state == TCP_ESTABLISHED || 
+			tp->state == TCP_FIN_WAIT1 ||
+			tp->state == TCP_FIN_WAIT2 ||
+			tp->state == TCP_CLOSE_WAIT)
+		atcp_send_bit(tp, TCP_FLAG_RST);
+
+	tp->state = TCP_CLOSE;
+	return 0;
+}
+
+struct common_protocol atcp_common_protocol = {
+	.size		= sizeof(struct atcp_protocol),
+	.connect	= &atcp_connect,
+	.process_in	= &atcp_process_in,
+	.process_out	= &atcp_process_out,
+	.destroy	= &atcp_destroy,
+};

-- 
	Evgeniy Polyakov

^ permalink raw reply related

* Re: [PATCH 2/3] [VLAN]: Update iif when receiving via VLAN device
From: Thomas Graf @ 2006-06-29  8:51 UTC (permalink / raw)
  To: jamal; +Cc: Patrick McHardy, David Miller, netdev
In-Reply-To: <1151502408.5203.94.camel@jzny2>

* jamal <hadi@cyberus.ca> 2006-06-28 09:46
> Why not use iflink?
> It exists, by definition, specifically as "the ifindex of the down muxed
> netdevice" (should probably add that definition in the .h).
> 
> This is semantically different from a message to the stack which says
> "this came to you from input device X" (represented by input_dev).

I disagree, iflink information is bogus once we start redirecting.

> > What's special about that? It seems a perfectly fine and simple way
> > to create namespaces for sockets without enforcing applications to
> > bind to the correct vlan devices directly.
> > 
> 
> Can you achieve the same by binding to any arbitrary netdevice? If you
> can then i would agree.

It was your request to not update input_dev in netif_receive_skb()
but rather have each netdevice handle it manually. What's currently
done in ifb:

	skb->dev = skb->input_dev;
	skb->input_dev = dev;

Confusing, isn't it? I really don't get input_dev/iif is supposed to
be updated in ifb. If a packet is to be redirected, the mirred action
shall take care of providing this information to the next netdevice.
My additional request is to provide a flag to disable this for special
purposes not hurting anyone.

> Please refer to what i said above in that you could end up redirecting
> many times. I have not added yet the code which allows mirred to also do
> ingress redirection which would make it even more interesting.
> The challenge is this, and if you can solve it we would be fine:
> - I need to access both the input_dev and dev and their metadata.
> I could clearly find them by their ifindices and then reference them
> after that. For performance reasons that is not optimal in the fast
> path.  

Nice, you forget that while redirecting the device pointed to by
input_dev can disappear leaving behind an illegal reference. The
purpose of this patch is to fix this.

^ permalink raw reply

* Re: bcm43xx: "transmit timed out" and apparent hang with "preemptible periodic work" patches
From: Paul Collins @ 2006-06-29  8:24 UTC (permalink / raw)
  To: Michael Buesch; +Cc: bcm43xx-dev, netdev, linville
In-Reply-To: <200606261727.24266.mb@bu3sch.de>

Michael Buesch <mb@bu3sch.de> writes:

> On Monday 26 June 2006 14:43, Michael Buesch wrote:
>> Try to get more logs.
>> I suggest to do a netconsole for logging.
>
> Also note that current softmac trees have a patch missing.
> It seems it got lost somewhere after my merge request.
> I already contacted John in private for this, but no reply, yet.
> The patch is attached. Maybe it fixes your issue.

On a preempt kernel I can trigger the hang easily, but alas nothing
further is printed on the console.

The "suspend MAC" patch does not help.  I also added the mac_suspended
patch, which does fix the assertion failures, but it still hangs after
some up/down-ing of the interface and an attempt to get an IP address
via DHCP as I normally do.

I still get the hang if I revert the preemptible periodic work patch
(91769e7dd9cef7988dc4280f74ed168351beb5b8) but if I revert the locking
pre-work too (78ff56a06edc3407996173daf63e48f6b90c7062) then it's
robust again.  I do get a TX timeout after I bounce the interface a
few times and then do DHCP, but it reinitialises the card and succeeds
in getting an IP address.


Below is what happens running Linus's current tree with the
mac-suspend and refcount patches applied.

(module loads)
  Jun 29 17:32:30 briny kernel: bcm43xx: Chip ID 0x4306, rev 0x3
  Jun 29 17:32:30 briny kernel: bcm43xx: Number of cores: 5
  Jun 29 17:32:30 briny kernel: bcm43xx: Core 0: ID 0x800, rev 0x4, vendor 0x4243, enabled
  Jun 29 17:32:30 briny kernel: bcm43xx: Core 1: ID 0x812, rev 0x5, vendor 0x4243, disabled
  Jun 29 17:32:30 briny kernel: bcm43xx: Core 2: ID 0x80d, rev 0x2, vendor 0x4243, enabled
  Jun 29 17:32:30 briny kernel: bcm43xx: Core 3: ID 0x807, rev 0x2, vendor 0x4243, disabled
  Jun 29 17:32:30 briny kernel: bcm43xx: Core 4: ID 0x804, rev 0x9, vendor 0x4243, enabled
  Jun 29 17:32:30 briny kernel: bcm43xx: PHY connected
  Jun 29 17:32:30 briny kernel: bcm43xx: Detected PHY: Version: 2, Type 2, Revision 2
  Jun 29 17:32:31 briny kernel: bcm43xx: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)
  Jun 29 17:32:31 briny kernel: bcm43xx: Radio turned off
  Jun 29 17:32:31 briny kernel: bcm43xx: Radio turned off

$ ip set link eth1 up

  Jun 29 17:32:48 briny kernel: bcm43xx: PHY connected
  Jun 29 17:32:49 briny kernel: bcm43xx: Radio turned on
  Jun 29 17:32:49 briny kernel: bcm43xx: Chip initialized
  Jun 29 17:32:49 briny kernel: bcm43xx: DMA initialized
  Jun 29 17:32:49 briny kernel: bcm43xx: 80211 cores initialized
  Jun 29 17:32:49 briny kernel: bcm43xx: Keys cleared
  Jun 29 17:32:49 briny kernel: SoftMAC: Open Authentication completed with XX:XX:XX:XX:XX:XX

$ ip set link eth1 down

  Jun 29 17:32:55 briny kernel: bcm43xx: Radio turned off
  Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0200 (RX) max used slots: 1/64
  Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0260 (TX) max used slots: 0/512
  Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0240 (TX) max used slots: 0/512
  Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0220 (TX) max used slots: 1/512
  Jun 29 17:32:55 briny kernel: bcm43xx: DMA 0x0200 (TX) max used slots: 0/512
  Jun 29 17:32:56 briny kernel: bcm43xx: PHY connected
  Jun 29 17:32:56 briny kernel: bcm43xx: Radio turned on
  Jun 29 17:32:56 briny kernel: bcm43xx: Chip initialized
  Jun 29 17:32:56 briny kernel: bcm43xx: DMA initialized
  Jun 29 17:32:56 briny kernel: bcm43xx: 80211 cores initialized
  Jun 29 17:32:56 briny kernel: bcm43xx: Keys cleared

(hmm, it didn't associate this time)
$ iwconfig eth1 essid wlan-ap enc off

  Jun 29 17:33:14 briny kernel: bcm43xx: set security called, .level = 0, .enabled = 0, .encrypt = 0
  Jun 29 17:33:14 briny kernel: SoftMAC: Open Authentication completed with XX:XX:XX:XX:XX:XX

$ ip set link eth1 down

  Jun 29 17:33:22 briny kernel: bcm43xx: Radio turned off
  Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0200 (RX) max used slots: 1/64
  Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0260 (TX) max used slots: 0/512
  Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0240 (TX) max used slots: 0/512
  Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0220 (TX) max used slots: 1/512
  Jun 29 17:33:22 briny kernel: bcm43xx: DMA 0x0200 (TX) max used slots: 0/512

$ ip set link eth1 up

  Jun 29 17:33:27 briny kernel: bcm43xx: PHY connected
  Jun 29 17:33:27 briny kernel: bcm43xx: Radio turned on
  Jun 29 17:33:27 briny kernel: bcm43xx: Chip initialized
  Jun 29 17:33:27 briny kernel: bcm43xx: DMA initialized
  Jun 29 17:33:27 briny kernel: bcm43xx: 80211 cores initialized
  Jun 29 17:33:27 briny kernel: bcm43xx: Keys cleared

$ iwconfig eth1 essid wlan-ap enc off

  Jun 29 17:33:31 briny kernel: bcm43xx: set security called, .level = 0, .enabled = 0, .encrypt = 0
  Jun 29 17:33:31 briny kernel: SoftMAC: Open Authentication completed with XX:XX:XX:XX:XX:XX

$ dhclient eth1

  Jun 29 17:33:41 briny kernel: NETDEV WATCHDOG: eth1: transmit timed out
  Jun 29 17:33:41 briny kernel: bcm43xx: Controller RESET (TX timeout) ...
  Jun 29 17:33:41 briny kernel: bcm43xx: Chip ID 0x4306, rev 0x3
  Jun 29 17:33:41 briny kernel: bcm43xx: Number of cores: 5
  Jun 29 17:33:41 briny kernel: bcm43xx: Core 0: ID 0x800, rev 0x4, vendor 0x4243, enabled
  Jun 29 17:33:41 briny kernel: bcm43xx: Core 1: ID 0x812, rev 0x5, vendor 0x4243, disabled
  Jun 29 17:33:41 briny kernel: bcm43xx: Core 2: ID 0x80d, rev 0x2, vendor 0x4243, enabled
  Jun 29 17:33:41 briny kernel: bcm43xx: Core 3: ID 0x807, rev 0x2, vendor 0x4243, disabled
  Jun 29 17:33:41 briny kernel: bcm43xx: Core 4: ID 0x804, rev 0x9, vendor 0x4243, enabled
  Jun 29 17:33:41 briny kernel: bcm43xx: PHY connected
  Jun 29 17:33:41 briny kernel: bcm43xx: Detected PHY: Version: 2, Type 2, Revision 2
  Jun 29 17:33:41 briny kernel: bcm43xx: Detected Radio: ID: 2205017f (Manuf: 17f Ver: 2050 Rev: 2)
  Jun 29 17:33:41 briny kernel: bcm43xx: Radio turned off
  Jun 29 17:33:41 briny kernel: bcm43xx: Radio turned off
  Jun 29 17:33:41 briny kernel: bcm43xx: Controller restarted

And here it hangs.

-- 
Paul Collins
Melbourne, Australia

Dag vijandelijk luchtschip de huismeester is dood

^ permalink raw reply

* Re: PATCH SB1250 NAPI support
From: Martin Michlmayr @ 2006-06-29  8:22 UTC (permalink / raw)
  To: jgarzik, netdev; +Cc: Tom Rix, mark.e.mason
In-Reply-To: <op.tamrhvwlthfl8t@localhost.localdomain>

* Tom Rix <trix@specifix.com> [2006-06-04 11:45]:
> A while ago I submitted this patch for NAPI support for SB1250 / SB1480.
> I have tested it again on the recent (6/3/06) linux-mips kernel.

Are there any comments regarding this patch (apart from the fact that
Tom forgot to include a Signed-off-by line).  Can it go in when it's
resent with a Signed-off-by line or does the patch have any other
problems?
-- 
Martin Michlmayr
tbm@cyrius.com

^ permalink raw reply

* Re: 2.6.17.1: fails to fully get webpage
From: CaT @ 2006-06-29  4:18 UTC (permalink / raw)
  To: David Miller; +Cc: linux-kernel, netdev
In-Reply-To: <20060628.204709.41634813.davem@davemloft.net>

On Wed, Jun 28, 2006 at 08:47:09PM -0700, David Miller wrote:
> You can save yourself that hassle by informing the site admin
> of the affected site that they have a firewall that misinterprets
> the RFC standard window scaling field of the TCP headers.  These
> devices assume it is zero because they don't remember the window
> scale negotiated at the beginning of the TCP connection.
> 
> Your TCP performance will suffer greatly if you disable window
> scaling across the board.  It means that only a 64K window will
> be usable by TCP, and you'll not be able to fill the pipe.
> 
> Please don't use a screwdriver to pound in a nail :)

Indeed. The hassle I'm thinking of is the reverse situation (and please
correct me if this does not apply). Say for example I run a web server.
I have customers and they have customers (lets call them CCs :). Somewhere
along the path between me and CCs there is such a misbehaving device.
The CCs try to get to my customers website and fail (I assume). If my
assumption is right, what's the probability of the CCs ever informing my
customer that there is a problem? I think it's more likely they would
just move on to another site offering the same thing, especially since
they would mostlikely need to load the site in order to get the
appropriate contact details.

Basically the mostlikely end-result is I don't know what there is a
problem and my customer doesn't know that there is a problem but they're
just not getting as many hits to their site that they otherwise would.

Ofcourse, this all depends if such a situation is possible. If it is
possible would it affect dns and mail in a similar manner too?

-- 
    "To the extent that we overreact, we proffer the terrorists the
    greatest tribute."
    	- High Court Judge Michael Kirby

^ permalink raw reply

* [PATCH] improved statistics for bcm43xx-softmac
From: Larry Finger @ 2006-06-29  4:08 UTC (permalink / raw)
  To: John Linville, netdev

This patch improves the statistics returned from bcm43xx_get_wireless_stats. The signal level comes
from smoothing the rssi value returned by the firmware. The quality value is a hack derived from the
smoothed rssi value and an assumed rssi_max of -25. If anyone has a better value, please let me
know. The noise value is still the one calculated from the clean-room formula. On my system, this is
roughly -65 dBm, which seems too high. I would appreciate getting any ideas on what other 
interface/driver combinations get for the noise value.

Signed-Off-By: Larry Finger <Larry.Finger@lwfinger.net>

==========================================================

diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index af97755..c80fdcd 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1581,17 +1581,8 @@ static void handle_irq_noise(struct bcm4
		else
			average -= 48;

-/* FIXME: This is wrong, but people want fancy stats. well... */
-bcm->stats.noise = average;
-		if (average > -65)
-			bcm->stats.link_quality = 0;
-		else if (average > -75)
-			bcm->stats.link_quality = 1;
-		else if (average > -85)
-			bcm->stats.link_quality = 2;
-		else
-			bcm->stats.link_quality = 3;
-//		dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
+/* FIXME: This matches the formula from the clean-room, but yields a value that is probably too
large. */
+		bcm->stats.noise = average;
  drop_calculation:
		bcm->noisecalc.calculation_running = 0;
		return;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index 5c36e29..8224da1 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -47,6 +47,8 @@ #include "bcm43xx_phy.h"
  #define BCM43xx_WX_VERSION	18

  #define MAX_WX_STRING		80
+/* FIXME: the next line is a guess as to what the maximum value of rssi might be */
+#define RSSI_MAX		-25


  static int bcm43xx_wx_get_name(struct net_device *net_dev,
@@ -227,15 +229,15 @@ static int bcm43xx_wx_get_rangeparams(st

	range->max_qual.qual = 100;
	/* TODO: Real max RSSI */
-	range->max_qual.level = 3;
-	range->max_qual.noise = 100;
-	range->max_qual.updated = 7;
-
-	range->avg_qual.qual = 70;
-	range->avg_qual.level = 2;
-	range->avg_qual.noise = 40;
-	range->avg_qual.updated = 7;
-
+	range->max_qual.level = -100;
+	range->max_qual.noise = -100;
+	range->max_qual.updated = IW_QUAL_ALL_UPDATED;
+
+	range->avg_qual.qual = 50;
+	range->avg_qual.level = -40;
+	range->avg_qual.noise = -65;
+	range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
+
	range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
	range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
	range->min_frag = MIN_FRAG_THRESHOLD;
@@ -827,6 +829,8 @@ static struct iw_statistics *bcm43xx_get
	struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
	struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
	struct iw_statistics *wstats;
+	struct ieee80211_network *network = NULL;
+	static int tmp_level = 0;

	wstats = &bcm->stats.wstats;
	if (!mac->associated) {
@@ -849,11 +853,19 @@ static struct iw_statistics *bcm43xx_get
		return wstats;
	}
	/* fill in the real statistics when iface associated */
-	wstats->qual.qual = 100;     // TODO: get the real signal quality
-	wstats->qual.level = 3 - bcm->stats.link_quality;
+	list_for_each_entry(network, &mac->ieee->network_list, list) {
+		if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
+			if (!tmp_level)		/* get initial value */
+				tmp_level = network->stats.rssi;
+			else			/* smooth results */
+				tmp_level = (7 * tmp_level + network->stats.rssi)/8;
+			break;
+		}
+	}
+	wstats->qual.level = tmp_level;
+	wstats->qual.qual = 100 + tmp_level - RSSI_MAX; // TODO: get the real signal quality
	wstats->qual.noise = bcm->stats.noise;
-	wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
-		IW_QUAL_NOISE_UPDATED;
+	wstats->qual.updated = IW_QUAL_ALL_UPDATED;
	wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
	wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
	wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;

==================


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox