Monday, February 06, 2006

Linksys WPC54G with FreeBSD

Yesterday I posted how I figured out how to use wlan_wep on FreeBSD. Today I received my new Linksys WPC54G wireless 802.11g network adapter. I decided to try using it with FreeBSD 6.0.

When I inserted it into the PCMCIA slot, I got these errors:

cardbus0: CIS pointer is 0!
cardbus0: Resource not specified in CIS: id=10, size=2000
cardbus0: at device 0.0 (no driver attached)

That didn't look good. I decided to use Bill Paul's ndis driver to get the Windows drivers working with FreeBSD. I posted about this capability two years ago, but today I used it in production.

I had previously tried the ndiscvt utility to turn Windows device drivers into something recognized by FreeBSD. Looking at the man pages, I soon learned of the new ndisgen a text-driven wizard to facilitate using ndis. Here's how it worked for me.

First (using a wired connection) I downloaded the latest version of the Windows drivers for my WPC54G. I saw the Linksys site offered downloads for WPC54G versions 1 through 5. Looking closely at the card itself, I saw I had version 3. (I saw nothing resembling a version number on the box.) I downloaded and extracted the 32 MB .zip containing the Windows files.

In the WPC54G Setup Wizard 3.1/Driver/NT directory I saw three files:

-rw-r--r-- 1 richard richard 8266 Apr 19 2005
-rw-r--r-- 1 richard richard 31738 Apr 19 2005 LSBCMNDS.inf
-rw-r--r-- 1 richard richard 371712 Feb 11 2005 bcmwl5.sys

The last two were the ones I needed. I copied them to /home/richard/tmp, and changed into that directory.

Next I started ndisgen and saw this screen. I decided to cut to the chase and begin at step 3.

------------------ Windows(r) driver converter -------------------

This script is designed to guide you through the process
of converting a Windows(r) binary driver module and .INF
specification file into a FreeBSD ELF kernel module for use
with the NDIS compatibility system.

The following options are available:

1] Learn about the NDIS compatibility system
2] Convert individual firmware files
3] Convert driver
4] Exit

Enter your selection here and press return: 3

Now I'm prompted for the .inf file:

------------------ Windows(r) driver converter -------------------

INF file validation

A .INF file is most often provided as an ASCII file, however
files with multilanguage support are provided in Unicode format.
Please type in the path to your .INF file now.

> /home/richard/tmp/LSBCMNDS.inf

This .INF file appears to be ASCII.

Press return to continue...

Now I'm prompted for the .sys file.

------------------ Windows(r) driver converter -------------------

Driver file validation

Now you need to specify the name of the Windows(r) driver .SYS
file for your device. Note that if you are running FreeBSD/amd64,
then you must provide a driver that has been compiled for the
64-bit Windows(r) platform. If a 64-bit driver is not available
for your device, you must install FreeBSD/i386 and use the
32-bit driver instead.

Please type in the path to the Windows(r) driver .SYS file now.

> /home/richard/bcmwl5.sys

This .SYS file appears to be in Windows(r) PE format.

Press return to continue...

Now I'm prompted for to confirm conversion.

------------------ Windows(r) driver converter -------------------

Driver file conversion

The script will now try to convert the .INF and .SYS files
using the ndiscvt(1) utility. This utility can handle most
.INF files; however, occasionally it can fail to parse some files
due to subtle syntax issues: the .INF syntax is very complex,
and the Windows(r) parser will sometimes allow files with small
syntax errors to be processed correctly which ndiscvt(1) will
not. If the conversion fails, you may have to edit the .INF
file by hand to remove the offending lines.

Press enter to try converting the files now:

Conversion was successful.

Press enter to continue...

There aren't any additional firmware files, so I hit enter below.

------------------ Windows(r) driver converter -------------------

Firmware file conversion

If your driver uses additional firmware files, please list them
below. When you're finished, just press enter to continue. (If your
driver doesn't need any extra firmware files, just press enter
to move to the next step.)


Nothing happens here.

------------------ Windows(r) driver converter -------------------

List of files converted firmware files:

Press enter to continue...

Now ndisgen creates a kernel module for me.

------------------ Windows(r) driver converter -------------------

Kernel module generation

The script will now try to generate the kernel driver module.
This is the last step. Once this module is generated, you should
be able to load it just like any other FreeBSD driver module.

Press enter to compile the stub module and generate the driver
module now:

Generating Makefile... done.
Building kernel module... done.
Cleaning up... done.

The file bcmwl5_sys.ko has been successfully generated.
You can kldload this module to get started.

Press return to exit.

My directory now has a kernel module for my wireless card.

orr:/home/richard/tmp$ ls -alh
total 868
drwxr-xr-x 2 richard richard 512B Feb 6 18:56 .
drwxr-xr-x 15 richard richard 1.0K Feb 6 18:55 ..
-rw-r--r-- 1 richard richard 31K Feb 6 18:52 LSBCMNDS.inf
-rw-r--r-- 1 richard richard 363K Feb 6 18:52 bcmwl5.sys
-rwxr-xr-x 1 richard richard 420K Feb 6 18:55 bcmwl5_sys.ko

I load the kernel module and check dmesg output.

orr:/home/richard/tmp$ sudo kldload ./bcmwl5_sys.ko
orr:/home/richard/tmp$ dmesg | grep ndis
ndis0: mem 0x88000000-0x88001fff irq 11 at device 0.0 on cardbus0
ndis0: NDIS API version: 5.1
ndis0: Ethernet address: 00:14:bf:22:be:12

Bingo. I have a ndis0 interface. Let's see it.

orr:/home/richard/tmp$ ifconfig ndis0
ndis0: flags=8802 mtu 1500
ether 00:14:bf:22:be:12
media: IEEE 802.11 Wireless Ethernet autoselect
status: no carrier
ssid "" channel 1
authmode OPEN privacy OFF txpowmax 100 protmode CTS

A look at the loaded kernel modules shows my custom kernel module, if_ndis, and ndis are loaded.

orr:/home/richard/tmp$ kldstat
Id Refs Address Size Name
1 18 0xc0400000 63072c kernel
2 2 0xc0a31000 74b0 snd_csa.ko
3 3 0xc0a39000 1d408 sound.ko
4 1 0xc0a57000 c3a4 r128.ko
5 2 0xc0a64000 eeec drm.ko
6 16 0xc0a73000 568dc acpi.ko
7 1 0xc2003000 69000 bcmwl5_sys.ko
8 1 0xc206c000 b000 if_ndis.ko
9 2 0xc2077000 13000 ndis.ko

Before I can bring up the card, I load the wlan_wep module as explained yesterday.

orr:/home/richard/tmp$ kldload wlan_wep

Now I'm ready to bring up the card.

orr:/home/richard/tmp$ sudo ifconfig ndis0 inet netmask ssid shaolin
wepkey 0xmykey deftxkey 1 wepmode on

No errors -- let's check ndis0

orr:/home/richard/tmp$ ifconfig ndis0
ndis0: flags=8843 mtu 1500
inet netmask 0xffffff00 broadcast
inet6 fe80::214:bfff:fe22:be12%ndis0 prefixlen 64 scopeid 0x4
ether 00:14:bf:22:be:12
media: IEEE 802.11 Wireless Ethernet autoselect (OFDM/54Mbps)
status: associated
ssid shaolin channel 1 bssid 00:13:10:65:2f:ad
authmode OPEN privacy ON deftxkey 1 wepkey 1:104-bit txpowmax 100
protmode CTS

Looks good -- I'll add a default route and ping Google.

orr:/home/richard/tmp$ sudo route add default
add net default: gateway
orr:/home/richard/tmp$ ping -c 1
PING ( 56 data bytes
64 bytes from icmp_seq=0 ttl=233 time=270.746 ms

--- ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max/stddev = 270.746/270.746/270.746/0.000 ms

Awesome. To make life easier, I copy my new kernel module to the location other kernel modules are stored.

orr:/home/richard/tmp$ sudo cp bcmwl5_sys.ko /boot/kernel/

Finally I create a short shell script to automate the process of bringing the card up once it's inserted.

kldload bcmwl5_sys
kldload wlan_wep
ifconfig ndis0 inet netmask ssid shaolin wepkey 0xmykey deftxkey 1 wepmode on
route add default

Everything works; in fact, I'm posting while using the card now.


Anonymous said...

It's great to know ndis works so easily.

I'd recommend putting the created module in /boot/modules instead of /boot/kernel so that it will survive your next upgrade or make installkernel.

See also the hier(7) manpage for distinctions between those directories. The full module search path can be seen in the loader with show module_path.

Sean C said...

Hi Richard,

Great post! Coming from a networking background, and just starting to touch UNIX, this actually made sense to me. I am still hesitant to install FreeBSD on an available box, but after reading your post, I'm willing to take a stab. Thanks again,

Anonymous said...

How do I know what default route I'm supposed to use?


Anonymous said...

Hi Richard,

This is a great blog you wrote about ndisgen. It could be treated as the best HOWTO I found on the net. I am trying to install the same card as you BCM 4306. Unfortunatelly this posed a number of problems. I do not see the device after loading the kernel modules. Could you please send me the INF & SYS files you used to thenasko _at_ gmail _dot_ com. I also experienced compilation problems with ndisgen from a full clean installation of FreeBSD 6.1 and I do not see any reason for this.

Any help will be greatly appreciated.


Arab said...

I needed to use latest windows driver version 7, but it gave me some errors with parsing, ndisgen asked me to fix the .inf manually which I don't know :(

Thank you,
Arab Portal

Anonymous said...

As a complete nooblet I found this post *most* useful for setting up my WPC54G on my first ever FreeBSD setup. Thanks, Ben

Ketev said...

This post is awesome. I have now fully gone over to FreeBSD on my Laptop. Prior to this I have not been able to get my wireless card working. Many thanks for this!

Anonymous said...

only problem I see is not sure what command to use for ESSID and the key to connect to router ??

I used iwconfig and script on startup in linux also needed to use ifconfig and that


which looks something like
iwconfig eth0 essid name
iwconfig eth0 key 00000
ifconfig eth0 up
hdcpcd eth0 auto
under sabayon linux 3.4e you no longer need to use the ndiswrapper to get your linksys card running it just works ...
but freebsd I think is still faster than linux in startup I think