1. 程式人生 > >Android軟體限制AP的最大連線數

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