转载:
Android SoftAp支持 (一)
Android SoftAp支持 (二)
java测试用例
WifiAP将wifi作为AP
一、概要介绍
1.JAVA API部分
frameworks/base/wifi/java/android/net/wifi/WifiManager.java
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
mService.setWifiApEnabled(wifiConfig, enabled);
}
public int getWifiApState() {
return mService.getWifiApEnabledState();
}
public boolean isWifiApEnabled() {
return getWifiApState() == WIFI_AP_STATE_ENABLED;
}
public WifiConfiguration getWifiApConfiguration() {
return mService.getWifiApConfiguration();
}
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
mService.setWifiApConfiguration(wifiConfig);
return true;
}
2.服务器端进程
frameworks/base/services/java/com/android/server/WifiService.java
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
}
public int getWifiApEnabledState() {
return mWifiStateMachine.syncGetWifiApState();
}
public WifiConfiguration getWifiApConfiguration() {
return mWifiStateMachine.syncGetWifiApConfiguration();
}
public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
mWifiStateMachine.setWifiApConfiguration(wifiConfig);
}
消息循环,状态机
frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java
public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enable) {
if (enable) {
sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_AP_STATE_ENABLING, 0));
sendMessage(obtainMessage(CMD_START_AP, wifiConfig));
} else {
sendMessage(CMD_STOP_AP);
sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_DISABLED, 0));
}
}
public void setWifiApConfiguration(WifiConfiguration config) {
mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
}
public WifiConfiguration syncGetWifiApConfiguration() {
Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
resultMsg.recycle();
return ret;
}
public int syncGetWifiApState() {
return mWifiApState.get();
}
public String syncGetWifiApStateByName() {
switch (mWifiApState.get()) {
case WIFI_AP_STATE_DISABLING:
return "disabling";
case WIFI_AP_STATE_DISABLED:
return "disabled";
case WIFI_AP_STATE_ENABLING:
return "enabling";
case WIFI_AP_STATE_ENABLED:
return "enabled";
case WIFI_AP_STATE_FAILED:
return "failed";
default:
return "[invalid state]";
}
}
class SoftApStartingState extends State {
@Override
public void enter() {
if (DBG) log(getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
final Message message = getCurrentMessage();
if (message.what == CMD_START_AP) {
final WifiConfiguration config = (WifiConfiguration) message.obj;
if (config == null) {
mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
} else {
mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
startSoftApWithConfig(config); //开启Ap功能
}
} else {
throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
}
}
@Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
switch(message.what) {
case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
WifiConfiguration config = (WifiConfiguration) message.obj;
if (config != null) {
startSoftApWithConfig(config); //开启Ap功能
} else {
loge("Softap config is null!");
sendMessage(CMD_START_AP_FAILURE);
}
break;
case CMD_START_AP_SUCCESS:
setWifiApState(WIFI_AP_STATE_ENABLED);
transitionTo(mSoftApStartedState);
break;
}
}
}
private void startSoftApWithConfig(final WifiConfiguration config) {
new Thread(new Runnable() {
public void run() {
try {
mNwService.startAccessPoint(config, mInterfaceName);
} catch (Exception e) {
loge("Exception in softap start " + e);
try {
mNwService.stopAccessPoint(mInterfaceName); //开启Ap功能
mNwService.startAccessPoint(config, mInterfaceName); //开启Ap功能
} catch (Exception e1) {
loge("Exception in softap re-start " + e1);
sendMessage(CMD_START_AP_FAILURE);
return;
}
}
if (DBG) log("Soft AP start successful");
sendMessage(CMD_START_AP_SUCCESS);
}
}).start();
}
3.NMS进程
frameworks/base/services/java/com/android/server/NetworkManagementService.java
public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
wifiFirmwareReload(wlanIface, "AP");
if (wifiConfig == null) {
mConnector.execute("softap", "set", wlanIface);
/*
mConnector = new NativeDaemonConnector(
new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 160);
*/
} else {
mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
getSecurityType(wifiConfig), wifiConfig.preSharedKey);
}
mConnector.execute("softap", "startap");
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
4.netd进程
system/netd/CommandListener.cpp
int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
if (!strcmp(argv[1], "startap")) {
rc = sSoftapCtrl->startSoftap();
} else if (!strcmp(argv[1], "stopap")) {
rc = sSoftapCtrl->stopSoftap();
} else if (!strcmp(argv[1], "fwreload")) {
rc = sSoftapCtrl->fwReloadSoftap(argc, argv);
} else if (!strcmp(argv[1], "clients")) {
rc = sSoftapCtrl->clientsSoftap(&retbuf);
if (!rc) {
cli->sendMsg(ResponseCode::CommandOkay, retbuf, false);
free(retbuf);
return 0;
}
} else if (!strcmp(argv[1], "status")) {
asprintf(&retbuf, "Softap service %s", (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));
cli->sendMsg(ResponseCode::SoftapStatusResult, retbuf, false);
free(retbuf);
return 0;
} else if (!strcmp(argv[1], "set")) {
rc = sSoftapCtrl->setSoftap(argc, argv);
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false);
return 0;
}
}
system/netd/SoftapController.cpp
int SoftapController::setSoftap(int argc, char *argv[]) {
if (argc > 3) {
ssid = argv[3];
} else {
ssid = (char *)"AndroidAP";
}
asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
"/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n",
iface, ssid);
if (argc > 4) {
if (!strcmp(argv[4], "wpa-psk")) {
generatePsk(ssid, argv[5], psk_str);
asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str);
} else if (!strcmp(argv[4], "wpa2-psk")) {
generatePsk(ssid, argv[5], psk_str);
asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);
} else if (!strcmp(argv[4], "open")) {
asprintf(&fbuf, "%s", wbuf);
}
} else {
asprintf(&fbuf, "%s", wbuf);
}
//static const char HOSTAPD_CONF_FILE[] = "/data/misc/wifi/hostapd.conf";
//配置文件/data/misc/wifi/hostapd.conf
fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660);
if (write(fd, fbuf, strlen(fbuf)) < 0) {
ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
ret = -1;
}
}
int SoftapController::startSoftap() {
if ((pid = fork()) < 0) {
ALOGE("fork failed (%s)", strerror(errno));
return -1;
}
if (!pid) {
ensure_entropy_file_exists();
if (execl("/system/bin/hostapd", "/system/bin/hostapd",
"-e", WIFI_ENTROPY_FILE,
HOSTAPD_CONF_FILE, (char *) NULL)) {
ALOGE("execl failed (%s)", strerror(errno));
}
ALOGE("Should never get here!");
return -1;
} else {
mPid = pid;
ALOGD("Softap startap - Ok");
usleep(AP_BSS_START_DELAY);
}
}
补充:
dnsmasq及dhcp相关
system/netd/TetherController.cpp
iptables相关
system/netd/NetdConstants.cpp
5.hostapd进程
external/wpa_supplicant_8/hostapd/main.c
int main(int argc, char *argv[])
{
}
external/wpa_supplicant_8/src/ap/hostapd.c
鉴权相关
external/wpa_supplicant_8/hostapd/src/ap/wpa_auth.c
二、测试
基于NT667-Android4.2平台
1.加载wifi驱动
uid=0 gid=0@android:/system/lib/modules # isnmod 8812au.ko
2.运行AP功能
hostapd -e /data/misc/wifi/entropy.bin /data/misc/wifi/hostapd.conf
vi /data/misc/wifi/hostapd.conf
interface=wlan0
driver=nl80211
ctrl_interface=/data/misc/wifi/hostapd
ssid=TanKaiSoftAP
#wpa_passphrase=0123456789
channel=6
ieee80211n=1
wpa=0
#wpa=2
rsn_pairwise=CCMP
wpa_psk=20c7dff358c6481bd7278907adb988b8ca7217bc407674b18a59b5c7f81bcc09
至此,可以搜索到SofrAP热点并连接上。
3.可以搜索到TanKaiSoftAP热点,并链接;卡在了获取IP地址这里
设置无线网卡IP
ifconfig wlan0 192.168.100.1 netmask 255.255.255.0
启动DHCP
dnsmasq --no-daemon --no-resolv --no-poll --dhcp-range=192.168.100.100,192.168.100.200,100h
当然也可以把相关配置写成文件再执行dnsmasq --conf-file=/*path*/dnsmasq.conf
至此,可以搜索到SoftAP并获取IP地址;但不能上外网。
5.可以获取IP地址,但不能上网;iptables设置
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -A FORWARD -i wlap0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i wlap0 -o eth0 -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
至此,软AP功能调通;手机连接具有软AP功能的电视可以正常访问外网。
三、wext驱动实现方式时的项目问题
我们使用的MTK平台SoftAP实现方式非Android标准;不使用hostapd,而且wifi驱动不是nl80211而是wext模式。
WIFI的Linux驱动部分wext和nl80211
转载:
MTK启动无线热点的过程
1.驱动加载
cd /system/lib/modules
insmod mt7601Uap.ko
ifconfig ra0 10.10.10.1
配置文件
/system/etc/Wireless/RT2870AP/RT2870AP.dat
卸载驱动
ifconfig ra0 down
rmmod mt7601Uap.ko
2.调试netd--ndc
转载:
Android 4.1 Netd详细分析(一)概述与应用实例
ndc是Android为Netd提供的一个测试工具。其主要功能有:
监视Netd中发生的事情。
支持通过命令行发送命令给Netd去执行。
ndc softap set ra0 TankaiMtk close
ndc softap startap
dnsmasq --no-daemon --no-resolv --no-poll --dhcp-range=10.10.10.100,10.10.10.200,100h
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -A FORWARD -i ra0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i ra0 -o eth0 -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
ndc softap stopap
ifconfig ra0 down
3.桥接
brctl addbr br0
brctl addif br0 eth0
brctl addif br0 ra0
ifconfig eth0 0.0.0.0
ifconfig ra0 0.0.0.0
ip link set br0 up
ip addr add 192.168.5.234/24 brd + dev br0
ip route add default via 192.168.5.254
移植brctl:
bridge-utils
运行报错:
add bridge failed: Package not installed
内核添加bridge支持:
linux-3.0/net/bridge/
make menuconfig
Networking support->Networking options->802.1d Ethernet Bridging