(wifi)android wifi移植(翻译)

本来想写一篇wifi移植的文章,但是想到panic大神的这篇文章,不敢造次,所以打算在原文的基础上给出翻译和解释,谨以此文纪念自己的职场菜鸟阶段。

原文链接:http://blog.linuxconsulting.ro/2010/04/porting-wifi-drivers-to-android.html


PaNiC Random Rant (or how we used to call it: .plan)


Porting WiFi drivers to Android
by Nicu Pavel on 11 August 2010

Update(19/05/2011): Verify validity against Gingerbread.
Update (11/08/2010): Updated patch to fix the loading of awext driver at run time.
Added STOP and RESTART commands.

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.

理解android wifi的工作原理


1. Enable building of wpa_supplicant in your BoardConfig.mk

修改BoardConfig.mk来build wpa_supplicant


2. (Optional) Enable debug for wpa_supplicant.

打开wpa_supplicant的debug信息


3. Provide a proper wpa_supplicant.conf for your device

给当前wifi设备提供一个合适的wpa_supplicant.conf


4. Have the correct paths and permissions created from init.rc

在init.rc里面给出正确的路径和权限


5. Make sure your wpa_supplicant and dhcpcd (optional) are starting from init.rc 

确保wpa_supplicant和dhcpcd从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.

通过修改android source code以module或者build in的方式提供driver


7. Provide a firmware if your module needs it.

提供driver module所需要的fireware


8. Make your driver work with Android custom wpa_supplicant commands and SIOCSIWPRIV ioctl
提供可以与supplicant work的driver和一些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

android使用一个修改过的wpa_supplicant(external/wpa_supplicant),android的ui通过frameworks/base/wifi/java/wifi/java/android/net/wifi的android.net.wifi包和他对应的jni接口,在wifi.c里面通过socekt的方式来控制supplicant,更高级的网络操作是在frameworks/base/core/java/android/net里面做的(这个是wifi的flow,看不懂的需要去自己看code)。


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).

在BoardConfig.mk里面配置wpa_supplicant

仅仅通过简单的配置BOARD_WPA_SUPPLICANT_DRIVER := WEXT,这将打开WPA_BUILD_SUPPLICANT这个define,然后来build driver_wext.c,如果你使用的wpa_supplicant是走madwifi等其他方式,你可以用MADWIFI或者其他的来代替WEXT。(panic前辈那时使用的主要是WEXT,现在android为了更好的支持wifi direct,基本上都用NL80211了)


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)

打开wpa_supplicant的debug信息

默认supplicant使用的是MSG_INFO,这个等级并不会给出很多打印信息

需要打开更多的debug信息

1修改common.c设置wpa_debug_level=MSG_DEBUG

2修改comman.h和xxx

(为了简单起见,可以在起supplicant的时候加上-ddd参数,这个会打印很多log,也可以使用wpa_cli log_level DEBUG来得到更多supplicant log)


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.

Minimum required config options in wpa_supplicant.conf :
- Android private socket

ctrl_interface=wlan0
update_config=1

- Unix standard socket

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=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
}

这个主要是wpa_supplicant.conf是supplicant的配置信息,需要注意的是ctrl_interface的值决定android wifi HAL与supplicant之间的通信方式,如果是wlan0的话说明使用android私有socket,如果使用/data/system/wpa_supplicant说明使用标准unix socket,另外根据driver需要配置其他信息,这里面后续会存入连线的一些profile。



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 ).

不正确的权限会导致wpa_supplicant不能创建/打开控制socket,这样子wifi HAL也就不能正常连接,自从Google修改supplicant,使之运行在wifi user/group,所以相应的路径和文件必须也属于wifi user/group


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:


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 control socket for android wifi.c (android private socket)
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
chown wifi wifi /data/misc/wifi

chown wifi wifi /data/misc/wifi/wpa_supplicant.conf

在init.rc里面添加上述的文件,主要作用是创建/system/etc/wifi/路径和路径里面的wpa_supplicant.conf和/data/msic/wifi/路径和wpa_supplicant.conf(其实data路径下面的wpa_supplicant.conf是system路径下的一份copy)



If you use a Unix standard socket in wpa_supplicant.conf (see above) add:

# wpa_supplicant socket (unix socket mode)
mkdir /data/system/wpa_supplicant 0771 wifi wifi
chmod 0771 /data/system/wpa_supplicant
chown wifi wifi /data/system/wpa_supplicant

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.

如果你使用的是unix socket的方式连接HAL和supplicant,还需要增加上述东西,主要是用来存放unix socket(还记得ctrl_interface=/data/system/wpa_supplicant的配置吗?)


5. Make sure your wpa_supplicant and dhcpcd are starting from init.rc

For wpa_supplicant the init.rc startup like should be depending on which path you chosen:
- Android private socket:

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

- Unix standard socket:

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

这里是建立一个wpa_supplicant的service,在HAL里面用ctl.start工具起这个service(作用就是按照一定的格式把supplicant run起来)


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

以同样的方式起一个dhcpcd的service(wifi连接成功之后就要用该方式去起一个dhcp client来拿ip,service的名字不重要,重要是该service到底干什么了,其实service的名字可以自己随意取)



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

其实现在这些define更多的是在wifi.c里面去做,在BoardConfig.mk里面写死的话局限性很大  


   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"

这两个property可以设置,也可以不设置,看自己的需要



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

如果driver需要,请提供driver的firamware,这个根据driver的需求来添加,一般是不需要的


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

 Android uses SIOCSIWPRIV ioctl to send commands to modify driver behaviour and receive information like signal strength, mac address of the AP, link speed etc. This ioctl is usually not implemented in any known wireless drivers except bcm4329 which is in google msm kernel branch .
The errors from not having this ioctl implemented will look like:
E/wpa_supplicant(  ): wpa_driver_priv_driver_cmd failed wpa_driver_priv_driver_cmd RSSI len = 4096  
E/wpa_supplicant(  ): wpa_driver_priv_driver_cmd failed  
D/wpa_supplicant(  ): wpa_driver_priv_driver_cmd LINKSPEED len = 4096
E/wpa_supplicant(  ): wpa_driver_priv_driver_cmd failed  
I/wpa_supplicant(  ): CTRL-EVENT-DRIVER-STATE HANGED

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.

这个是driver的工作方式的配置,目前driver都是工作在NL80211方式下的,只要配置对了就不会有什么问题


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

AWEXT driver patch download:   android_wext_emulation_driver_awext.patch

这个说的就是在BoardConfig.mk里面配置driver的工作方式

For Gingerbread patches see the post above.


总结一下,其实现在的wifi porting没有panic前辈说的那么多要注意的,如果是在原生的基础上去做改动,需要改的就两个部分:

(1)load driver部分,修改load driver路径为自己driver的路径,这样子wifi在打开的时候就会去load 自己需要的driver

(2)起supplicant部分,修改起supplicant的service为自己的supplicant启动的命令和参数,这样子supplicant在启动的时候就会按照自己的命令和参数启动自己的supplicant

有了上面两个部分的修改之后,HAL给supplicant发command这个是通用的,所以不用修改,上层ui通过framework,以jini的方式call 到HAL层,最后发给suppliant,下到driver的flow就建立起来了,这样子你就可以使用自己porting的wifi了,就这么多东西。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值