For mini-box.com picoPC we want to support several USB and miniPCI WiFi dongles, this guide provides a step by step explanation of what's involved in adding a new wifi driver and making wifi work in a custom Android build (this guide was written for android 2.1 but should be applicable to previous android releases and hopefully future releases). Contents
0. Understand how Android WiFi works.
1. Enable building of wpa_supplicant in your BoardConfig.mk
2. (Optional) Enable debug for wpa_supplicant.
3. Provide a proper wpa_supplicant.conf for your device
4. Have the correct paths and permissions created from init.rc
5. Make sure your wpa_supplicant and dhcpcd (optional) are starting from init.rc
6. Provide your driver either as a module or built in kernel and proper kernel support for it and modify Android source code accordingly.
7. Provide a firmware if your module needs it.
8. Make your driver work with Android custom wpa_supplicant commands and SIOCSIWPRIV ioctl

Now onto details.

0. Understand how Android WiFi works.
Android uses a modified wpa_supplicant ( external/wpa_supplicant ) daemon for wifi support which is controlled through a socket by hardware/libhardware_legacy/wifi/wifi.c (WiFiHW) that gets controlled from Android UI through android.net.wifi package from frameworks/base/wifi/java/android/net/wifi/ and it's corresponding jni implementation in frameworks/base/core/jni/android_net_wifi_Wifi.cpp Higher level network management is done in frameworks/base/core/java/android/net

1. Enable building of wpa_supplicant in your BoardConfig.mk
This is by simply adding: BOARD_WPA_SUPPLICANT_DRIVER := WEXT to your BoardConfig.mk . This will set WPA_BUILD_SUPPLICANT to true in external/wpa_supplicant/Android.mk enabling building of driver_wext.c
If you have a custom wpa_supplicant driver (like madwifi or my custom android private commands emulation - see last paragraph) you can replace WEXT with AWEXT or your driver name (MADWIFI, PRISM etc).

2. (Optional) Enable debug for wpa_supplicant.
By default wpa_supplicant is set to MSG_INFO that doesn't tell much.
To enable more messages:
2.1 modify common.c and set wpa_debug_level = MSG_DEBUG
2.2 modify common.h and change #define wpa_printf from if ((level) >= MSG_INFO) to if ((level) >= MSG_DEBUG)

3. Provide a proper wpa_supplicant.conf for your device
Providing a wpa_supplicant.conf it's important because the control socket for android is specified in this file (ctrl_interface= ). This file should be copied by your AndroidBoard.mk to $(TARGET_OUT_ETC)/wifi (usually /system/etc/wifi/wpa_supplicant.conf ). This location will be used on wpa_supplicant service from init.rc.
There are two different ways in which wpa_supplicant can be configured, one is to use a "private" socket in android namespace, created by socket_local_client_connect() function in wpa_ctrl.c and another is by using a standard unix socket.

If you have AP association problems with should change to ap_scan=0 to let the driver do the association instead of wpa_supplicant.
If you want to let wpa_supplicant connect to non-WPA or open wireless networks (by default it skips these kind) add:

network={
key_mgmt=NONE
}

4. Have the correct permissions and paths created from init.rc
Incorrect permisions will result in wpa_supplicant not being able to create/open the control socket and libhardware_legacy/wifi/wifi.c won't connect.
Since Google modified wpa_supplicant to run as wifi user/group the directory structure and file ownership should belong to wifi user/group (see os_program_init() function in wpa_supplicant/os_unix.c ).

Otherwise errors like:
E/WifiHW ( ): Unable to open connection to supplicant on "/data/system/wpa_supplicant/wlan0": No such file or directory will appear.

Also wpa_supplicant.conf should belong to wifi user/group because wpa_supplicant will want to modify this file. If your system has /system as read-only use a location like /data/misc/wifi/wpa_supplicant.conf and modify wpa_supplicant service in init.rc with new location.
Make sure the paths are correctly created in init.rc:

Do not add these if you use Android private socket because it will make wpa_supplicant non-functional, because hardware/libhardware_legacy/wifi/wifi.c check for existence of the /data/system/wpa_supplicant folder and will pass a wrong interface name to wpa_ctrl_open() function.

If your wifi driver creates a wifi interface with other name than wlan0 you will have to modify the above line accordingly.
You also should have dhcpcd starting from init.rc
service dhcpcd /system/bin/dhcpcd wlan0
group system dhcp
disabled
oneshot

Newer AOSP versions after Gingerbread use dhcpcd_wlan0 as service name.

6. Provide your driver either as a module or built in kernel and proper kernel support for it.
First make sure that CONFIG_PACKET and CONFIG_NET_RADIO (wireless extensions) are enabled in your kernel. The driver can be built as module (default android way) or built in kernel (if you want to rely in kernel auto probing to support multiple driver eg. USB wifi) but will require source code modifications (see below). - As kernel module:
Define in your BoardConfig.mk :
1. WIFI_DRIVER_MODULE_PATH := path to the module to be loaded
You need to specify module name in that path too, usually should look something like /system/lib/modules/wlan.ko
2. WIFI_DRIVER_MODULE_NAME:= the name of the network interface that the driver creates, for example wlan0
3. WIFI_DRIVER_MODULE_ARG:= any arguments that you want to pass to the driver on insmod, for example nohwcrypt

Make sure you copy your kernel module when building android to the correct location. - As built in kernel:
- First init.rc needs to be modified to inform hardware/libhardware_legacy/wifi/wifi.c about the name of the interface, that the driver is already loaded and set the status of wpa_supplicant to running:
setprop wifi.interface "wlan0"
setprop wlan.driver.status "ok"

Do NOT add setprop init.svc.wpa_supplicant "running" as I previously mentioned as it will prevent wpa_supplicant from starting from init.
- Secondly hardware/libhardware_legacy/wifi/wifi.c need to be modified so the functions insmod() and rmmod() return 0 (simply add return 0; as the first line in functions since they are not needed when driver is built in kernel) and return before checking for /proc/modules in check_driver_loaded() function.
You might encounter problems with WifiHW module not being able to connect to wpa_supplicant socket even with the correct permisions. Try to turn off / turn on Wifi from the GUI.

7. Provide a firmware if your driver needs it

If your driver needs a firmware you will have to copy this firmware file to /etc/firmware on your android build. Android doesn't use a standard hotplug binary (although there is an implementation available on android-x86 system/code/toolbox/hotplug.c ) instead the init process takes care of firmware events and loads the firmware file from /etc/firmware (see: system/core/init/devices.c handle_firmware_event() function).
Firmware file name is defined by the driver and might also contain a folder like: RTL8192SU/rtl8192sfw.bin, entire file path should be available in /etc/firmware

8. Make your driver work with Android custom wpa_supplicant commands and SIOCSIWPRIV ioctl.

After 4, WEXT_NUMBER_SEQUENTIAL_ERRORS errors, android will abort using the device.

To quickly test your wifi from interface you can disable error checking in external/wpa_supplicant/driver_wext.c by simply making ret = 0; in wpa_driver_priv_driver_cmd() function after the SIOCSIWPRIV ioctl call. This will make all access points in android UI appear without signal or MAC address.
To proper implement the ioctl you will need to modify your kernel driver to reply to SIOCSIWPRIV ioctl with RSSI (signal strength) and MACADDR commands being the most important.
A better way is to add a custom driver_xxx.c to google external/wpa_supplicant/ implementing wpa_driver_priv_driver_cmd() function that will take care of RSSI, MACADDR and others, through calls to SIOCGIWSTATS, SIOCGIFHWADDR ioctls, with the rest of the functions being called from driver_wext.c.
Below is a link to a patch for wpa_supplicant that I did for mini-box.com picoPC Android build. It creates a new driver awext which "emulates" android driver commands using wireless extensions ioctls.

56 Comments:

Hi, Was trying the same but have been facing some errors. E/WifiHW ( ): Unable to open connection to supplicant on "/data/system/wpa_supplicant/wlan0"Even though i have added permissions as mentioned. Would like to compare my files with yours. Would you mind sharing a copy of the modified files ? Thanks Yonathana

Also try to turnoff/turnon wifi, maybe wpa_supplicant hasn't yet created the socket. I've seen this on my build.You should see something similar to this in logcat (if you enabled wpa_supplicant debug):

This is what i did panic : drop both your files in the respective dir and cross check in the rfs if they are same Check permissions of s -l /data/system-rw-rw-r-- system system 35326 2000-01-01 00:00 packages.xml-rw------- system system 8 2000-01-01 00:01 syncmanager.prefsdrwxrwx--x system system 2000-01-01 00:00 registered_servicesdrwxrwxrwx wifi wifi 2000-01-01 00:00 wpa_supplicant-rw------- system system 4096 2000-01-01 00:00 entropy.dat-rw------- system system 171 2000-01-01 00:00 wallpaper_info.xml-rw-rw---- system system 16384 2000-01-01 00:00 accounts.db-rw------- system system 604 2000-01-01 00:00 batterystats.bindrwx------ system system 2000-01-01 00:00 usagestats-rw------- system system 64 2000-01-01 00:00 appwidgets.xml

I/ActivityManager( 802): Starting activity: Intent { act=android.intent.action.MAIN cmp=com.android.settings/.WirelessSettings }D/dalvikvm( 802): GC freed 9763 objects / 499352 bytes in 96msI/ActivityManager( 802): Displayed activity com.android.settings/.WirelessSettings: 556 ms (total 556 ms)W/WifiHW ( 802): Could not open /proc/modules: No such file or directoryI/StatusBarPolicy( 802): received intent android.net.wifi.WIFI_STATE_CHANGEDD/SettingsWifiEnabler( 985): Received wifi state changed from Disabled to EnablingD/WifiService( 802): ACTION_BATTERY_CHANGED pluggedType: 1E/WifiHW ( 802): Unable to open connection to supplicant on "/data/system/wpa_supplicant/wlan0": No such file or directoryD/SettingsWifiEnabler( 985): Received wifi state changed from Enabling to EnabledI/StatusBarPolicy( 802): received intent android.net.wifi.WIFI_STATE_CHANGEDE/WifiHW ( 802): Unable to open connection to supplicant on "/data/system/wpa_supplicant/wlan0": No such file or directoryE/WifiHW ( 802): Unable to open connection to supplicant on "/data/system/wpa_supplicant/wlan0": No such file or directoryI/StatusBarPolicy( 802): received intent android.intent.action.TIME_TICKE/WifiHW ( 802): Unable to opeinit: no such service 'dhcpcdwlan0'n connection to supplicant on "/data/system/wpa_supplicant/wlan0": No such file or directoryV/WifiStateTracker( 802): Supplicant died unexpectedlyE/WifiStateTracker( 802): Could not stop DHCPD/NetworkStateTracker( 802): setDetailed state, old =IDLE and new state=DISCONNECTEDD/ConnectivityService( 802): ConnectivityChange for WIFI: DISCONNECTED/DISCONNECTEDI/EthernetService( 802): setEthState from 2 to 2init: no such service 'dhcpcdwlan0'D/SettingsWifiEnabler( 985): Received wifi state changed from Enabled to DisablingI/StatusBarPolicy( 802): received intent android.net.wifi.supplicant.CONNECTION_CHANGEI/StatusBarPolicy( 802): received intent android.net.wifi.WIFI_STATE_CHANGED

Dear sir, I had setup my device with wpa_supplicant working good. But the message "ioctl[SIOCGIWRATE]: No such device" is showed after linkspeed command parsed by driver_awext.c. Would you please help me to figure out where to setup the correct interface in this situation? Thank you~

@ point 4if you use dhcp in init.rc you should also add a working folder.

mkdir /data/misc/dhcp 0770 dhcp dhcpchmod 0770 /data/misc/dhcp

@ point 5you have to use the wpa_supplicant.conf in /data/misc/wifi because in /system/etc/wifi/ is only a template which is write protected. to save configured networks you need to have write access to the conf file.

Hi, I followed the steps to enable wifi on froyo. wifi is getting enabled but when tried to connect it is not setting system properties like dhcp.eth0.ipaddress and other. it is setting only dhcp.eth0.dns1, dhcp.eth0.dns2 and dns3. whether I need to configure or change to set all system properties?

If you are interested, I have done it for supplicant 0.6.10: it's here:http://git.alwaysinnovating.com/cgit.cgi/ai.android/tree/preprocess/froyo/wifi.patchThe only notable difference is .get_scan_results2

I'd like very much to speak to you about your informative post on porting Wi-Fi drivers to Android. Are you interested in freelance consulting work? I'd be really grateful if you could contact me - blake@hfield.com. I look forward to hearing from you.

First, thank you for your shares, it really helps me a lot. Now I have a question of supporting multi-WiFi drivers at the same time. Is there any possibility not to init interface name(ex.wlan0,wpa_supplicant -iwlan0 -c xxxxx......) in init.rc? Because different WiFi drivers have different interface names. Or could you provide any other suggestions for this purpose? My work-arounded solution is to modify the same interface name for different WiFi drivers in src code(ex.wlan0). Then modify wifi.c(hardware\libhardware_legacy\wifi) to load different WiFi modules base on VID/PID table, which I've added for this purpose. But I think it's not a good solution. I'd appreciate of your comments. Thank you for your kindly help again.

Might be possible with gingerbread, since I've seen that the wpa_supplicant and dhcp are now started from wifi.c in hardware_legacy/wifiYou will need to modify wifi.c to get the interface name from sysfs and build up the wpa_supplicant command.

i am using panda board runs Android ICS and the on board wifi interface is enabled "wlan0"Now i am trying to add another interface "wlan1" to android and i want when i enable the wifi on the GUI it turns on my interface , i have succeeded to do so with wpa_supplicant by setting wifi.interface wlan1 , but the problem is with the DHCP , the DHCP is always trying to run over wlan0 not wlan1Is there is any property that i can sit to convince the GUI to run the DHCP over wlan1?

I have a hardware device very similar to the O2 joggler. Specifically it is an Atom-based Openpeak Openframe 7E.

There are some great Android builds out there for it's sister device, the o2 Joggler, but that device has a different WiFi radio.

http://www.jogglerwiki.com/forum/viewtopic.php?f=2&t=196&start=240

As a result it appears that the joggler image mentioned doesn't have the necessary WiFi driver for the Openframe hardware.

The Wireless hardware in the OpenFrame, verified by lspci, is the BCM43225. From this site, I believe the driver would be the brcmsmac.

Assuming that makes sense so far, here's my goal. I'd like to add the appropriate Android driver for this WiFi hardware to the custom build mentioned above. I believe it would entail the addition of the .ko driver, as well as the .bin firmware files as you outline.

My challenge, however, is that I cannot find an Android driver (.ko) already built, nor have I been able to verify that adding that driver would actually work.

Naively I took an ubuntu version of the brcmsmac.ko, added it to my device, and ran insmod on it. That errors out and fails to load.

Any suggestions? Any questions that would help clarify what I'm trying to do?

Bottom line, I have an andriod image that's 99% of the way there, I just need to "add" support for the specific wireless device installed in my hardware.

@AT you will need to get the kernel source for that device, and compile the kernel module for the wifi. It probably fails because of missmatched kernel version / arch. The ubuntu compiled .ko won't work since it's compiled for another kernel and probably with another march flags.

But... one thing I miss, very basic I think. I have prepared my wpa_supplicant.conf and I have built my driver from the kernel. So, in opedr to pick them with my Andorid build, in my full_.mk I've added these copy operations:

I had downloaded the android ICS source code from google repositories.I am able to compile and run the source code and build for emulator is working superb.Then I decided to burn on device Huawei Ascend G300 U8818.I had downloaded the Device configuration from github repository.Now I started compiling for Huawei device.When I execute the command make -j4 then I get the following error

make: *** No rule to make target `out/target/product/u8818/obj/STATIC_LIBRARIES/lib_driver_cmd_wext_intermediates/lib_driver_cmd_wext.a', needed by `out/target/product/u8818/obj/EXECUTABLES/wpa_supplicant_intermediates/LINKED/wpa_supplicant'. St

Please help in me.I am googling for almost 15 days but no guide no clues.Thank You.

I had downloaded the android ICS source code from google repositories.I am able to compile and run the source code and build for emulator is working superb.Then I decided to burn on device Huawei Ascend G300 U8818.I had downloaded the Device configuration from github repository.Now I started compiling for Huawei device.When I execute the command make -j4 then I get the following error

make: *** No rule to make target `out/target/product/u8818/obj/STATIC_LIBRARIES/lib_driver_cmd_wext_intermediates/lib_driver_cmd_wext.a', needed by `out/target/product/u8818/obj/EXECUTABLES/wpa_supplicant_intermediates/LINKED/wpa_supplicant'. St

Please help in me.I am googling for almost 15 days but no guide no clues.Thank You.

I will start working on ICS version in a few weeks. But probably rowboat, cyanogen might already have these patches ported to ICS so it's worth checking them out too.Regarding the issue where wifi automatically turns off after enabling it, it's because it can't ifup the interface (missing firmware, driver has other name for interface instead of wlan0). Check logcat it should tell you more.

I've amanged to complete the integration on GB and now I'm porting to JB. issue is that in GB I used to have the "wifi" option enabled under wireless settings, even before integrating the driver etc, while I miss this in JB. Any idea what could be missing?

I do follow you guide.But when I use "svc wifi enable" to start wifi,it's very hard to connect to AP.When I start wpa_supplicant by start wpa_supplicant,It works,but need to set the ip address by myself(my network use static ip address).

I want to know that ,if there is a way to use android's origin wifi controller,instead of add the wpa_supplicant service?