Android Wi-Fi — IP forward — ndc — netd
http://trac.gateworks.com/wiki/Android/wireless
Android uses the standard hostapd and wpa_supplicant users-space daemons for Access Point and authentication management. These are fairly close forks of the upstream projects with some changes specifically for Android. Source for both is currently in the external/wpa_supplicent_8 directory. Currently this relates most closely to the version 2.1-devel branch.
The Android network daemon netd (source in /system/netd) manages the overall Linux based network configuration listening for commands over a socket interface. There is a Network Daemon Command shell application, ndc that can be used to send/receive commands via command-line.
The wifi legacy module in hardware/hardware_liblegacy/wifi.c implements the API defined in hardware/libhardware_legacy/include/hardware_legacy/wifi.h
Build-time Configuration
The BoardConfig.mk file for your build target defines the details of the configuration of hostapd and wpa_supplicant used in the build process.
The Gateworks Android BSP defines the following:
# wireless device (used by various modules to include per-device support) BOARD_WLAN_DEVICE := wl12xx_mac80211 # Supplicant WPA_SUPPLICANT_VERSION := VER_0_8_X BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_wl12xx # skip populating rtl/conf files SKIP_WPA_SUPPLICANT_RTL := y SKIP_WPA_SUPPLICANT_CONF := y # AP HOSTAPD_VERSION := VER_0_8_x BOARD_HOSTAPD_DRIVER := NL80211 BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_wl12xx
- the wl12xx configuration and library are fairly mac80211 compliant and thus should provide support for all mac80211 drivers we include
- the 'PRIVATE_LIB's are used when communicating with the driver and allow for easy customization
Additional defines can be used for drivers that require specific kernel modules to be loaded or firmware to be loaded for various operation modes. The actual loading of the modules and firmware is done by wifi.c:
# kernel modules WIFI_DRIVER_MODULE_PATH - full path of kernel module(s) WIFI_DRIVER_MODULE_NAME - kernel module name (w/o the ko) WIFI_DRIVER_MODULE_ARG - kernel module params WIFI_DRIVER_P2P_MODULE_ARG # firmware WIFI_FIRMWARE_LOADER - firmware loader WIFI_DRIVER_FW_PATH_PARAM - params to pass to fw loader WIFI_DRIVER_FW_PATH_AP - full path to AP firmware WIFI_DRIVER_FW_PATH_STA - full path to STA firmware WIFI_DRIVER_FW_PATH_P2P - full path to P2P firmware
- Note by default these are all blank or null meaning not used and the Gateworks BSP does not define these meaning it supports wireless devices that either need no module/firmware loading or that it is assumed that was done during init.sh
Android Framework API
The Android framework talks to {{{netd}} via the NetworkManagementService class
The WifiManager class provides the primary API for managing al aspects of Wi-Fi connectivity. To perform operations that pertain to network connectivity at an abstract level use ConnectivityManager which answers queries about the state of network connectivity and notifies applications when network connectivity changes.
The WifiConfiguration class reprsents a configured Wi-Fi network, including the security configuration. Android is not intended to provide a build that is suitable for all wireless devices and you may find that customization via the above is necessary.
Packages
The Android modules/packages required for wireless are:
- client mode: wpa_supplicant
- access point mode: hostapd hostapd_cli dnsmasq iptables
Firmware and Kernel Module loading
The libhardware_legacy module provides an API used by the Android framework that facilitates kernel module loading, firmware loading, wpa_supplicant service management, and dhcp service management. The module is heavily configurable for specific wireless devices at build-time through:
- BoardConfig.mk variables:
# kernel Module WIFI_DRIVER_MODULE_NAME WIFI_DRIVER_MODULE_PATH WIFI_DRIVER_MODULE_ARG # Firmware WIFI_FIRMWARE_LOADER WIFI_DRIVER_FW_PATH_STA WIFI_DRIVER_FW_PATH_AP WIFI_DRIVER_FW_PATH_P2P WIFI_DRIVER_FW_PATH_PARAM
- functions and their native JNI mappings via WifiNative class:
- driver loading/unloading (used by android_net_wifi_WifiNative.cpp)
- wifi_load_driver() / loadDriver
- wifi_unload_driver() / unloadDriver
- is_wifi_driver_loaded() / isDriverLoaded
- supplicant (used by android_net_wifi_WifiNative.cpp)
- wifi_start_supplicant() / startSupplicant
- wifi_stop_supplicant() / killSupplicant
- wifi_connect_to_supplicant() / connectToSupplicantNative
- wifi_close_supplicant_connection() / closeSupplicantConnectionNative
- configuration (used by android_net_wifi_WifiNative.cpp)
- wifi_wait_for_event() / waitForEventNative
- wifi_command() / doBoolenaCommandNative / doIntCommandNative / doStringCommandNative
- DHCP
- do_dhcp_request()
- get_dhcp_error_string()
- firmware loading (used by SoftapController.cpp)
- wifi_get_fw_path()
- wifi_change_fw_path()
- driver loading/unloading (used by android_net_wifi_WifiNative.cpp)
- paths for the user-space daemons are stored in wifi.c
Client Mode
Android uses the standard wpa_supplicant users-space daemon for Access Point and authentication management on the client-side.
Configuration
The wpa_supplicant.conf file is stored in /data/misc/wifi/wpa_supplicant.conf and used by the WifiConfigStore class and the SettingsBackupAgent class
Operation
The wpa_supplicant application runs as a backgaround daemon launched by the Android init process. It is communicated with via a socket.
Android UI
You can use Wireless Networking Client support via the Settings App: Settings -> Wi-Fi. You must enable Wi-Fi and configure one or more Wi-Fi networks at which point the NetworkManagementService? will handle the associations.
Android Application
An Application can use Wireless Client mode via the WifiConfiguration class (representing a configured Wi-Fi network including security) and the WifiManager class functions:
- setWifiEnabled() - Enable or disable Wi-Fi
- getWifiState() - get wi-Fi enabled state
- isWifiEnabled() - return whether Wi-Fi is enabled or disabled
- startScan() - request a scan for access points
- getScanResults() - returnteh results of the latest access point scan
command-line
From a command-line perspective you can manually configure and launch wpa_supplicant if you wish:
# restore default wpa_supplicant.conf and start wpa_supplicant service
cp /system/etc/wifi/wpa_supplicant.conf /data/misc/wifi/wpa_supplicant
chmod 660 /data/misc/wifi/wpa_supplicant.conf
chwon system.wifi /data/misc/wifi/wpa_supplicant.conf
start wpa_supplicant
Access Point Mode
Android uses the hostapd users-space daemon for Access Point and authentication management on the AP side. For a DHCP server it uses the typical dnsmasq server.
The hostapd application provides the Access Point management and is managed by the netd SoftapController class which accepts the following commands:
- startap - starts hostapd
- stopap - stops hostapd
- fwreload <STA|AP|P2P> - reload firmware for specified operating mode
- status - returns if AP is running or not
- set <wlan iface> <SSID <hidden|broadcast> <channel> <wpa2?-psk|open> <passphrase> - configure AP
The dnsmasq application provides a DHCP server and is managed by the netd TetherController class which also manages iptables.
The netd TetherController class accepts the following commands:
which accesps the following commands.
- tether stop - stop tethering
- tether start - start tethering
- tether status - report tether status
- tether interface add <iface> - add an interface to the tether
- tether interface remove <iface> - remove an interface from the tether
- tether interface list - list tethered interfaces
- tether dns set <dns1> <...> - add 1 or more dns forwarders
- tether dns list - list dns forwarders
Network Address Translation (NAT) is provided by the netd NatController class which uses the iptables shell command and accepts the following commands:
- nat enable <internal interface> <externalinterface> [<route-rules...>] - enable NAT
- route-rules take the form of: <action> <addr> what will be used with the ip tool as: ip rule <action> from <addr> table
- nat disable <internal interface> <externalinterface> - disable NAT
Configuration
The hostapd.conf file is stored in /data/misc/wifi/hostapd.conf and used by the SoftapController class.
The dnsmasq application is launched by netd with all configuration available on the cmdline. It will store lease information in /data/misc/dhcp/dnsmasq.leases
When configuration through the Android UI, the Settings application (Settings -> Wireless & Networks -> More... -> Tethering & portable hotspot -> Set up Wi-Fi hotspot) will store the SSID and Passkey settings in the /data/misc/wifi/softap.conf file which are used to dynamically create /data/misc/wifi/hostapd.conf.
Operation
Unlike other system services that are started from Android's init process, hostapd is started on-demand by the Network Daemon netd via it's !SoftapController class when it receives the softap startap command.
This command is sent to netd when the NetworkManagementService startAccessPoint function is called.
Android UI
From an Android UI perspective, you can enable an Access Point (aka Hotspot) and NAT routing (aka Tethering) via the Settings Application:
- Goto Settings -> Wireless & Networks -> More... -> Tethering & portable hotspot -> Set up Wi-Fi hotspot and specify your SSID and security settings
- Goto Settings -> Wireless & Networks -> More... -> Tethering & portable hotspot -> Portable Wi-Fi hotspot
Note that enabling the Wi-Fi hotspot via the Settings GUI will not 'stick' and again be enabled on re-boot by design.
Android Application
An application can use the WifiManager class to manage an Access Point:
- setWifiApEnabled() - start AP Mode
- getWifiApState() - get Wi-Fi AP enabled state
- isWifiApEnabled() - return whether Wi-Fi AP is enabled or disabled
- getWifiApConfiguration() - get the Wi-Fi AP configuration
- setWifiApConfiguration() - set the Wi-Fi AP configuration
If your wireless device requires module or firmware loading, netd will do this as well by calling fwreload <STA|AP|P2P> using the API defined in hardware/libhardware_legacy/include/wifi.h however note that the firmware load command and patches for each option are a build-time option using paths and arguments defined in BoardConfig.mk. By default these are all blank meaning no firmware or modules will be loaded.
command-line
While you can manage hostapd and dnsmasq IP forwarding, and Network Address Translation manually it is likely much easier to use the API that the Network Daemon netd provides either through the Android java framework via the NetworkManagementService class or via command-line with its command-line interface app netd.
For example, you can use netd to manage an Access Point with Linux NAT Routine (aka a 'Tethered Hotspot') using ncd:
- configure Access Point:
ndc softap set wlan0 testssid broadcast 11 wpa-psk testpass # config hostapd
- the softap set command has the usage: sotfap set <iface> <SSID> <hidden|broadcast> <channel> <wpa-psk|wpa2-psk|open> <passphrase>
- /data/misc/wifi/hostapd.conf (which must be writable by netd) will be written to:
interface=<iface> driver=nl80211 ctrl_interface=/data/misc/wifi/hostapd ssid=testssid channel=<channel> ieee80211n=1 hw_mode=g
- for hidden an 'ignore_broadcast_ssid=1' will be added, for broadcast 'ignore_broadcast_ssid=0'
- for wpa-psk 'wpa=1, wpa_pairwise=TKIP CCMD, wpa_psk' entries will be added
- for wpa2-psk 'wpa=2, rsn_pairwise=CCMP, wpa_psk' entries will be added
- /data/misc/wifi/hostapd.conf (which must be writable by netd) will be written to:
- the softap set command has the usage: sotfap set <iface> <SSID> <hidden|broadcast> <channel> <wpa-psk|wpa2-psk|open> <passphrase>
- start the Access Point:
ndc softap startap # start hostapd
- Note that you can stop the Access Point at any time with ncd softap stopap
- configure the wlan0 interface:
ndc interface setcfg wlan0 192.168.43.1 24 up
- configure tethering
ndc tether interface add wlan0 # add wlan0 to tether ndc tether dns set 8.8.4.4 8.8.8.8 # add DNS servers ndc ipfwd enable # enable IP forwarding
- start tether of wlan0 with a specified DHCP pool (.10 to .99 in this case) (runs dnsmasq and configures NAT)
ndc tether start 192.168.43.10 192.168.43.99
- start Network Address Translation (NAT)
ndc nat enable wlan0 eth0 0
Note that when using Access Point mode, you must not enable Wireless from the Settings Application as this puts the radio in Client mode.