Porting WiFi drivers to Android

orting WiFidrivers to Android 

For mini-box.com picoPC we want to support several USB and miniPCIWiFi dongles, this guide provides a step by step explanation ofwhat's involved in adding a new wifi driver and making wifi work ina custom Android build  (this guide was writtenfor android 2.1 but should be applicable to previous androidreleases 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 frominit.rc
5. Make sure your wpa_supplicant and dhcpcd (optional) are startingfrom init.rc 
6. Provide your driver either as a module or built in kernel andproper kernel support for it and modify Android source codeaccordingly.
7. Provide a firmware if your module needs it.
8. Make your driver work with Android custom wpa_supplicantcommands 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 byhardware/libhardware_legacy/wifi/wifi.c that gets controlled fromAndroid UI through android.net.wifi package fromframeworks/base/wifi/java/android/net/wifi/ and it's correspondingjni implementation inframeworks/base/core/jni/android_net_wifi_Wifi.cpp. Higher levelnetwork management is done inframeworks/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 ofdriver_wext.c
If you have a custom wpa_supplicant driver (like madwifi) you canset in BOARD_WPA_SUPPLICANT_DRIVER := MADWIFI.


2. (Optional) Enable debug for wpa_supplicant.

By default wpa_supplicant is set to MSG_INFO that doesn't tellmuch. To enable more messages:
  2.1 modify common.c and set wpa_debug_level =MSG_DEBUG
  2.2 modify common.h and change #definewpa_printf from #ifdef ANDROID to if ((level) >=MSG_DEBUG) instead of if ((level) >= MSG_INFO)

3. Provide a proper wpa_supplicant.conf for your device

Providing a wpa_supplicant.conf it's important because the controlsocket for android is specified in this file (ctrl_interface= ).This file should be copied by your AndroidBoard.mk to$(TARGET_OUT_ETC)/wifi (basically/system/etc/wifi/wpa_supplicant.conf).
This location should be double checked on init.rc for servicewpa_supplicant as the wpa_supplicant config file.

Minimum required config options in wpa_supplicant.conf :

ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=wifi
update_config=1

Depending on your driver you might also want to add:

ap_scan=1

If you have AP association problems with should change to ap_scan=0to let the driver do the association instead ofwpa_supplicant.

If you want to let wpa_supplicant connect to non-WPA or openwireless networks (by default it skips these kind) add:

network={
key_mgmt=NONE
}

4. Have the correct permissions and paths created frominit.rc

Incorrect permisions will result in wpa_supplicant not being ableto create/open the control socket andlibhardware_legacy/wifi/wifi.c won't connect.
Since Google modified wpa_supplicant to run as wifi user/group thedirectory structure and file ownership should belong to wifiuser/group (see os_program_init() function inwpa_supplicant/os_unix.c).

Otherwise errors like:

E/WifiHW  ): Unable to openconnection to supplicant on "/data/system/wpa_supplicant/wlan0": Nosuch file or directory will appear.

Also wpa_supplicant.conf should belong to user/group wifi becausewpa_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_supplicantservice in init.rc with new location.

Make sure the paths are correctly created in init.rc:

mkdir /system/etc/wifi 0770 wifi wifi
chmod 0770 /system/etc/wifi
chmod 0660 /system/etc/wifi/wpa_supplicant.conf
chown wifi wifi /system/etc/wifi/wpa_supplicant.conf
# wpa_supplicant socket
mkdir /data/system/wpa_supplicant 0771 wifi wifi
chmod 0771 /data/system/wpa_supplicant
#wpa_supplicant control socket for android wifi.c
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
chmod 0770 /data/misc/wifi
chmod 0660 /data/misc/wifi/wpa_supplicant.conf

5. Make sure your wpa_supplicant and dhcpcd are starting frominit.rc

For wpa_supplicant the init.rc startup like should be:

service wpa_supplicant /system/bin/wpa_supplicant -dd -Dwext-iwlan0 -c /system/etc/wifi/wpa_supplicant.conf
group system wifi inet
disabled
oneshot

If your wifi driver creates a wifi interface with other name thenwlan0 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

6. Provide your driver either as a module or built in kernel andproper kernel support for it.

 First make sure that CONFIG_PACKET and CONFIG_NET_RADIO (wireless extensions) areenabled in your kernel. The driver can be built as module (defaultandroid way) or built in kernel (if you want to rely in kernel autoprobing to support multiple driver eg. USB wifi) but will requiresource code modifications (see below).

 - As kernel module:

   Define in yourBoardConfig.mk:

   1. WIFI_DRIVER_MODULE_PATH:=
      You need to specify module name in that path too, usually shouldlook something like /system/lib/modules/wlan.ko

   2. WIFI_DRIVER_MODULE_NAME:= for example wlan0

   3. WIFI_DRIVER_MODULE_ARG:=for example nohwcrypt

  
   Make sure you copy your kernelmodule when building android to the correct location.


- As built in kernel:

  - First init.rc needs to be modified to informhardware/libhardware_legacy/wifi/wifi.c about the name of theinterface, that the driver  is already loaded andset the status of wpa_supplicant to running:

setprop wifi.interface "wlan0"
setprop wlan.driver.status "ok"
setprop init.svc.wpa_supplicant "running"

 - Secondlyhardware/libhardware_legacy/wifi/wifi.c need to be modified so thefunctions to insmod/rmmod return 0 (simply add return 0; as thefirst line in functions since they are not needed when driver isbuilt in kernel) and return before checking for /proc/modulesin  check_driver_loaded() function.


 7. Provide a firmware if your driver needsit

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


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

 Android uses SIOCSIWPRIV ioctl to send commandsto driver and receive information like signal strength, mac addressof the AP, link speed. This ioctl is usually not implemented in anyknown wireless drivers except bcm4329 which is in google msm kernelbranch.

The errors from not having this ioctl implemented will looklike:

E/wpa_supplicant(  ): wpa_driver_priv_driver_cmdfailed wpa_driver_priv_driver_cmd RSSI len = 4096
E/wpa_supplicant(  ): wpa_driver_priv_driver_cmdfailed
D/wpa_supplicant(  ): wpa_driver_priv_driver_cmdLINKSPEED len = 4096
E/wpa_supplicant(  ): wpa_driver_priv_driver_cmdfailed
I/wpa_supplicant(  ): CTRL-EVENT-DRIVER-STATEHANGED

After 4, WEXT_NUMBER_SEQUENTIAL_ERRORS errors android will abortusing the device.

To quickly test your wifi from interface you can disable errorchecking in external/wpa_supplicant/driver_wext.c by simply makingret = 0; in wpa_driver_priv_driver_cmd() function after the ioctlcall. This will make all access points in android UI appear withoutsignal or MAC address.

To proper implement the ioctl you will need to modify your kerneldriver 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 googleexternal/wpa_supplicant/ implementing wpa_driver_priv_driver_cmd()function that will take care of RSSI and MACADDR through a call to SIOCGIWSTATS ioctl and the rest of the functionscan be called from driver_wext.c.

Below is a link to a patch for wpa_supplicant that I did formini-box.com picoPC Android build. It creates a new driver awextwhich "emulates" android driver commands using wireless extensionsioctls.

How to use the new driver:

1. In your BoardConfig.mk define: BOARD_WPA_SUPPLICANT_DRIVER :=AWEXT
2. Change init.rc wpa_supplicant service command line by replacind-Dwext with -Dawext


Patch download: 0001-Added-a-separate-driver-awext-to-emulate-Android-dri.patch
【接下篇】

原文地址:https://www.cnblogs.com/yuzaipiaofei/p/4124627.html