最近有个需要是要做成AP的最大连接数用户可配置,此处不讨论硬件限制,仅仅从软件方面去对Android源码做修改。
让/data/misc/wifi/hostapd.conf里面带上max_num_sta参数即可达到目的,例如要限制成10个,则max_num_sta=10。
Android原生代码不包含此参数,/data/misc/wifi/hostapd.conf会在AP开启的时候由/system/bin/netd通过softap set参数设置下去,查看netd相关源码,可以看到最后的配置文件是由system/netd/SoftapController.cpp中的SoftapController::setSoftap()函数根据java层传过来的参数设置的。
最简单的方式是使用原有的argv[5],也就是Channel值,修改成包含Channel和max_num_sta两个值的参数,上层传参数时把这两个值合成,SoftapController::setSoftap()函数再把值解析出来即可,修改如下:
/*
* Arguments:
* argv[2] - wlan interface
* argv[3] - SSID
* argv[4] - Broadcast/Hidden
* argv[5] - Channel
* argv[6] - Security
* argv[7] - Key
*/
int SoftapController::setSoftap(int argc, char *argv[]) {
int hidden = 0;
int channel = AP_CHANNEL_DEFAULT;
int max_num_sta = 0;//add for sta limit 20180921
if (argc < 5) {
ALOGE("Softap set is missing arguments. Please use:");
ALOGE("softap ");
return ResponseCode::CommandSyntaxError;
}
if (!strcasecmp(argv[4], "hidden"))
hidden = 1;
if (argc >= 5) {
channel = atoi(argv[5]);
//start add for sta limit 20180921
char buf[PROPERTY_VALUE_MAX] = {'\0',};
if (property_get("persist.sys.softap.limit", buf, "0")) {
max_num_sta = (channel >> 16) & 0xFFFF;
channel &= 0xFFFF;
}
//end add for sta limit 20180921
if (channel <= 0)
channel = AP_CHANNEL_DEFAULT;
}
std::string wbuf;
if(max_num_sta) {
std::string wbuf_tmp(StringPrintf("interface=%s\n"
"driver=nl80211\n"
"ctrl_interface=/data/misc/wifi/hostapd\n"
"ssid=%s\n"
"channel=%d\n"
"ieee80211n=1\n"
"hw_mode=%c\n"
"ignore_broadcast_ssid=%d\n"
"wowlan_triggers=any\n"
"max_num_sta=%d\n",
argv[2], argv[3], channel, (channel <= 14) ? 'g' : 'a', hidden, max_num_sta));
wbuf = wbuf_tmp;
}
else {
std::string wbuf_tmp(StringPrintf("interface=%s\n"
"driver=nl80211\n"
"ctrl_interface=/data/misc/wifi/hostapd\n"
"ssid=%s\n"
"channel=%d\n"
"ieee80211n=1\n"
"hw_mode=%c\n"
"ignore_broadcast_ssid=%d\n"
"wowlan_triggers=any\n",
argv[2], argv[3], channel, (channel <= 14) ? 'g' : 'a', hidden));
wbuf = wbuf_tmp;
}
std::string fbuf;
if (argc > 7) {
char psk_str[2*SHA256_DIGEST_LENGTH+1];
if (!strcmp(argv[6], "wpa-psk")) {
generatePsk(argv[3], argv[7], psk_str);
fbuf = StringPrintf("%swpa=3\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf.c_str(), psk_str);
} else if (!strcmp(argv[6], "wpa2-psk")) {
generatePsk(argv[3], argv[7], psk_str);
fbuf = StringPrintf("%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf.c_str(), psk_str);
} else if (!strcmp(argv[6], "open")) {
fbuf = wbuf;
}
} else if (argc > 6) {
if (!strcmp(argv[6], "open")) {
fbuf = wbuf;
}
} else {
fbuf = wbuf;
}
if (!WriteStringToFile(fbuf, HOSTAPD_CONF_FILE, 0660, AID_SYSTEM, AID_WIFI)) {
ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
return ResponseCode::OperationFailed;
}
return ResponseCode::SoftapStatusResult;
}
至于java层的修改则是修改WifiConfiguration类,添加一个apMaxNumSta字段,并修改WifiConfiguration相关操作函数增加对此值的处理,最后通过NetworkManagementService.startAccessPoint把值传下去,修改如下:
@Override
public void startAccessPoint(
WifiConfiguration wifiConfig, String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
if (wifiConfig == null) {
mConnector.execute("softap", "set", wlanIface);
} else {
if (SystemProperties.getInt("persist.sys.softap.limit", 0) != 0 && wifiConfig.apMaxNumSta != 0) {
int mix = (wifiConfig.apMaxNumSta << 16) | wifiConfig.apChannel ;
//start add by gerhard.lao for sta limit 20180921
Slog.d(TAG, "startAccessPoint apMaxNumSta " + wifiConfig.apMaxNumSta +
"apChannel " + wifiConfig.apChannel + "mix " + mix);
mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
"broadcast", Integer.toString(mix),
getSecurityType(wifiConfig),
new SensitiveArg(wifiConfig.preSharedKey));
//end add by gerhard.lao for sta limit 20180921
} else {
mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
"broadcast", Integer.toString(wifiConfig.apChannel),
getSecurityType(wifiConfig),
new SensitiveArg(wifiConfig.preSharedKey));
}
}
mConnector.execute("softap", "startap");
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
这样,上层使用的时候设置apMaxNumSta即可带到native层然后写/data/misc/wifi/hostapd.conf,最终开启AP的时候会根据此参数限制最大连接数。
或者使用更简单直接的方式:
SoftapController::setSoftap()读取persist.sys.softap.limit值然后如果是非0值就应用到配置里面:
/*
* Arguments:
* argv[2] - wlan interface
* argv[3] - SSID
* argv[4] - Broadcast/Hidden
* argv[5] - Channel
* argv[6] - Security
* argv[7] - Key
*/
int SoftapController::setSoftap(int argc, char *argv[]) {
int hidden = 0;
int channel = AP_CHANNEL_DEFAULT;
if (argc < 5) {
ALOGE("Softap set is missing arguments. Please use:");
ALOGE("softap ");
return ResponseCode::CommandSyntaxError;
}
if (!strcasecmp(argv[4], "hidden"))
hidden = 1;
if (argc >= 5) {
channel = atoi(argv[5]);
if (channel <= 0)
channel = AP_CHANNEL_DEFAULT;
}
//start add for sta limit 20180921
int max_num_sta = 0;
char buf[PROPERTY_VALUE_MAX] = {'\0',};
if (property_get("persist.sys.softap.limit", buf, "0")) {
max_num_sta = atoi(buf);
if(max_num_sta != 0) {
if(max_num_sta < 0 || max_num_sta > 255)
max_num_sta = 0;
}
}
//end add for sta limit 20180921
std::string wbuf;
if(max_num_sta) {
std::string wbuf_tmp(StringPrintf("interface=%s\n"
"driver=nl80211\n"
"ctrl_interface=/data/misc/wifi/hostapd\n"
"ssid=%s\n"
"channel=%d\n"
"ieee80211n=1\n"
"hw_mode=%c\n"
"ignore_broadcast_ssid=%d\n"
"wowlan_triggers=any\n"
"max_num_sta=%d\n",
argv[2], argv[3], channel, (channel <= 14) ? 'g' : 'a', hidden, max_num_sta));
wbuf = wbuf_tmp;
}
else {
std::string wbuf_tmp(StringPrintf("interface=%s\n"
"driver=nl80211\n"
"ctrl_interface=/data/misc/wifi/hostapd\n"
"ssid=%s\n"
"channel=%d\n"
"ieee80211n=1\n"
"hw_mode=%c\n"
"ignore_broadcast_ssid=%d\n"
"wowlan_triggers=any\n",
argv[2], argv[3], channel, (channel <= 14) ? 'g' : 'a', hidden));
wbuf = wbuf_tmp;
}
std::string fbuf;
if (argc > 7) {
char psk_str[2*SHA256_DIGEST_LENGTH+1];
if (!strcmp(argv[6], "wpa-psk")) {
generatePsk(argv[3], argv[7], psk_str);
fbuf = StringPrintf("%swpa=3\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf.c_str(), psk_str);
} else if (!strcmp(argv[6], "wpa2-psk")) {
generatePsk(argv[3], argv[7], psk_str);
fbuf = StringPrintf("%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf.c_str(), psk_str);
} else if (!strcmp(argv[6], "open")) {
fbuf = wbuf;
}
} else if (argc > 6) {
if (!strcmp(argv[6], "open")) {
fbuf = wbuf;
}
} else {
fbuf = wbuf;
}
if (!WriteStringToFile(fbuf, HOSTAPD_CONF_FILE, 0660, AID_SYSTEM, AID_WIFI)) {
ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
return ResponseCode::OperationFailed;
}
return ResponseCode::SoftapStatusResult;
}