Netgear MA401 Wireless Drivers on Debian

steel, a Toshiba Satellite 4060XCDT running Debian Etch, has a Netgear MA401 Wireless pcmcia card. By default, the orinoco_cs driver was used for this card. While running with a DHCP-assigned address, I had experienced no problems with it, but when I assigned steel's eth0 port a static address (to expose it to the Internet), I noticed that every six minutes, if there was no ethernet traffic, these messages would appear:

  Apr 26 10:23:51 steel kernel: eth0: New link status: Disconnected (0002)
  Apr 26 10:23:53 steel kernel: eth0: New link status: Connected (0001)
  Apr 26 10:29:51 steel kernel: eth0: New link status: Disconnected (0002)
  Apr 26 10:29:52 steel kernel: eth0: New link status: Connected (0001)
  Apr 26 10:35:51 steel kernel: eth0: New link status: Disconnected (0002)
  Apr 26 10:35:52 steel kernel: eth0: New link status: Connected (0001)

While looking for other reports of this behaviour, I found that the hostap_cs driver would also work with the Netgear card. I had already noticed that both the orinoco_cs and hostap_cs drivers were shown by lsmod as loaded. Maybe one was interfering with the other?

This lead to a slight detour, as I became interested in how the modules were chosen and loaded. Digging around in the udev material at http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html (link removed as kernel.org is down) gave me a lot of info; I also found a useful article which explained how the modalias system worked.

Back on track. To test the idea of module interference, I added hostap_cs to the /etc/modprobe.d/blacklist file. However, even without the hostap_driver loaded, the same disconnection pattern occurred. The next thing to try was to use the hostap_cs driver and see if that cured the problem. This was slightly more tricky.

Firstly, I modified the /etc/modprobe.d/blacklist file, removing hostap_cs and adding orinoco_cs. Then I had to modify the original udev rules in /etc/udev/rules.d/z25_persistent-net.rules to comment out the eth0 naming that was created when I first installed Debian:

  # This file was automatically generated by the /lib/udev/write_net_rules
  # program, probably run by the persistent-net-generator.rules rules file.
  #
  # You can modify it, as long as you keep each rule on a single line.
  # MAC addresses must be written in lowercase.

  # PCI device 0x1179:0x060f (orinoco_cs)
  #SUBSYSTEM=="net", DRIVERS=="?*", ATTRS{address}=="00:09:5b:3b:90:23", NAME="eth0"

This is because the naming convention offered by hostap_cs is wifi0 and wlan0. The also meant a matching modification to the /etc/network/interfaces file.

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
# This will be used for the wired ethernet card, and the Netgear MA401
# with the orinoco_cs driver (uncomment auto eth0 line to use)
#auto eth0
allow-hotplug eth0
iface eth0 inet dhcp
    wireless-mode managed
    wireless-power off
    wireless-ap 00:16:E6:3C:B2:4B
    wireless-essid hydrus
    wireless-key1 deadbeef00

# Netgear MA401 wireless card with hostap_cs driver
auto wlan0
allow-hotplug wlan0
iface wlan0 inet dhcp
#   wireless-* options are implemented by the wireless-tools package
    wireless-mode managed
    wireless-ap 00:16:E6:3C:B2:4B
    wireless-essid hydrus
    wireless-key1 deadbeef00

Then I stopped networking, soft ejected the wireless card, removed the orinoco_cs module and re-inserted the card:

  /etc/init.d/networking stop
  pccardctl eject
  modprobe -r orinoco_cs
  pccardctl insert

resulting in the following messages, and a working hostap_cs driven wireless card:

  Apr 27 11:20:16 steel kernel: pccard: card ejected from slot 0
  Apr 27 11:20:22 steel kernel: pccard: PCMCIA card inserted into slot 0
  Apr 27 11:20:22 steel kernel: pcmcia: registering new device pcmcia0.0
  Apr 27 11:20:22 steel kernel: hostap_cs: Registered netdevice wifi0
  Apr 27 11:20:22 steel kernel: hostap_cs: index 0x01: , irq 3, io 0x0100-0x013f
  Apr 27 11:20:22 steel kernel: wifi0: NIC: id=0x800c v1.0.0
  Apr 27 11:20:22 steel kernel: wifi0: PRI: id=0x15 v1.0.7
  Apr 27 11:20:22 steel kernel: wifi0: STA: id=0x1f v1.3.6

The /etc/udev/rules.d/z25_persistent-net.rules now looked like this:

  # This file was automatically generated by the /lib/udev/write_net_rules
  # program, probably run by the persistent-net-generator.rules rules file.
  #
  # You can modify it, as long as you keep each rule on a single line.
  # MAC addresses must be written in lowercase.

  # PCI device 0x1179:0x060f (orinoco_cs)
  #SUBSYSTEM=="net", DRIVERS=="?*", ATTRS{address}=="00:09:5b:3b:90:23", NAME="eth
  0"

  # PCI device 0x1179:0x060f (hostap_cs)
  SUBSYSTEM=="net", DRIVERS=="?*", ATTRS{address}=="00:09:5b:3b:90:23", ATTRS{type
  }=="1", NAME="wlan0"

Sadly, while the reset behaviour changed, it was not eliminated, as this extract from /var/log/messages shows:

  Apr 27 11:26:58 steel kernel: ADDRCONF(NETDEV_CHANGE): wifi0: link becomes ready
  Apr 27 11:34:57 steel kernel: ADDRCONF(NETDEV_CHANGE): wifi0: link becomes ready
  Apr 27 11:43:56 steel kernel: ADDRCONF(NETDEV_CHANGE): wifi0: link becomes ready
  Apr 27 11:52:55 steel kernel: ADDRCONF(NETDEV_CHANGE): wifi0: link becomes ready

Well, I can't blame the orinoco_cs driver for the problem. So, the ADDRCONF message comes from IPV6 and, if my digging through the code is to be believed, it a symptom not a cause, as it is invoked as the result of some device change.

I started the process to rebuild the hostap_cs module with debugging turned on, following this recipe, now a little outdated, so here's a summary:

  make clean
  make mrproper
  # make dep is no longer required
  make menuconfig
  make SUBDIRS=drivers/net/wireless/hostap modules

However, on examining the code, I realised debugging was already turned on, as was obvious once I looked at /var/log/debug. This log showed that the hostap_cs driver was doing exactly the same thing as the orinoco_cs driver:

  Apr 27 12:57:04 steel kernel: wifi0: LinkStatus=2 (Disconnected)
  Apr 27 12:57:04 steel kernel: wifi0: LinkStatus: BSSID=00:16:e6:3c:b2:4b
  Apr 27 12:57:06 steel kernel: wifi0: LinkStatus=1 (Connected)
  Apr 27 12:57:06 steel kernel: wifi0: LinkStatus: BSSID=00:16:e6:3c:b2:4b
  Apr 27 13:03:03 steel kernel: wifi0: LinkStatus=2 (Disconnected)
  Apr 27 13:03:03 steel kernel: wifi0: LinkStatus: BSSID=00:16:e6:3c:b2:4b
  Apr 27 13:03:05 steel kernel: wifi0: LinkStatus=1 (Connected)
  Apr 27 13:03:05 steel kernel: wifi0: LinkStatus: BSSID=00:16:e6:3c:b2:4b

Looking at the hostap code, it seemed the only way this LinkStatus message could appear was in response to a device interrupt, since it was issued via a tasklet.

Hmm, maybe the problem was my wireless router. I tested this by using an old wireless access point, a Dlink 900AP+. When the Netgear card was associated with this - no resets. So the problem must either reside entirely within the wireless router, or in the combination of the Netgear card and the router.

At this point I gave up and used the ugly fix, adding the following line to /etc/crontab:

  */5 *   * * *   root    ping -c 1 78.32.224.137 >/dev/null

which had the effect of pinging the router every five minutes, ensuring whatever timer was being triggered was reset before it fired.

Switching from a default DHCP-assigned IP address to static address (for exposure to the evils of the Internet) was slightly more complicated with the hostap_cs driver. With the orinoco_cs driver, I could get away with issuing ifconfig commands. With the hostap_cs driver, this caused various errors:

  Apr 27 18:08:35 steel kernel: wlan0: MAC port 0 enabling failed
  Apr 27 18:08:35 steel kernel: wlan0: could not enable MAC port
  Apr 27 18:12:09 steel kernel: CNFWEPFLAGS reading failed
  Apr 27 18:12:27 steel kernel: hostap_cs: Shutdown failed
  Apr 27 18:12:28 steel kernel: hostap_cs: Initialization failed
  Apr 27 18:12:31 steel kernel: wifi0: interrupt delivery does not seem to work
  Apr 27 18:12:33 steel kernel: wifi0: interrupt delivery does not seem to work
  Apr 27 18:13:20 steel kernel: hostap_cs: wifi0: resetting card
  Apr 27 18:17:10 steel kernel: hostap_cs: wifi0: resetting card

I therefore used the following script to convert from a DHCP address to a static IP:

  /etc/init.d/networking stop           # bring down interface; stop dhclient
  pccardctl eject
  cp /root/interfaces.static /etc/network/interfaces
  pccardctl insert 
  cat << >/etc/resolv.conf     # have to use external nameservers
  search hydrus.org.uk
  nameserver 195.74.113.58
  nameserver 195.74.113.62
  EOF
  /etc/init.d/networking start
  cp /root/interfaces.dhcp /etc/network/interfaces

The interfaces.static and interfaces.dhcp contain different interface specifications for static and dhcp setup respectively.