Android軟體限制AP的最大連線數
最近有個需要是要做成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 <wlan iface> <SSID> <hidden/broadcast> <channel> <wpa2?-psk|open> <passphrase>"); 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 <wlan iface> <SSID> <hidden/broadcast> <channel> <wpa2?-psk|open> <passphrase>");
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;
}