From ed4475ebb170e9912201d162a8ffa5d6bbd636b9 Mon Sep 17 00:00:00 2001 From: Mygod Date: Sat, 29 May 2021 14:58:46 -0400 Subject: [PATCH] Support for multi-band SACC --- README.md | 3 + .../be/mygod/vpnhotspot/RepeaterService.kt | 6 +- .../vpnhotspot/manage/RepeaterManager.kt | 7 +- .../net/wifi/SoftApConfigurationCompat.kt | 69 ++++++++++++++----- .../net/wifi/WifiApDialogFragment.kt | 3 +- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 89f2d1d2..6ddee0ce 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,7 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setBlockedClientList(Ljava/util/List;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setBssid(Landroid/net/MacAddress;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setChannel(II)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` +* (since API 31) `Landroid/net/wifi/SoftApConfiguration$Builder;->setChannels(Landroid/util/SparseIntArray;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setClientControlByUserEnabled(Z)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setHiddenSsid(Z)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setMaxNumberOfClients(I)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` @@ -248,12 +249,14 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setSsid(Ljava/lang/String;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->BAND_2GHZ:I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->BAND_5GHZ:I,sdk,system-api,test-api` +* (since API 31) `Landroid/net/wifi/SoftApConfiguration;->BAND_60GHZ:I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->BAND_6GHZ:I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->BAND_ANY:I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getAllowedClientList()Ljava/util/List;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getBand()I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getBlockedClientList()Ljava/util/List;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getChannel()I,sdk,system-api,test-api` +* (since API 31) `Landroid/net/wifi/SoftApConfiguration;->getChannels()Landroid/util/SparseIntArray;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getMaxNumberOfClients()I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getShutdownTimeoutMillis()J,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->isAutoShutdownEnabled()Z,sdk,system-api,test-api` diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt index d3184f49..25b2cf3a 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt @@ -378,10 +378,12 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene setPassphrase(passphrase) when (val oc = operatingChannel) { 0 -> setGroupOperatingBand(when (val band = operatingBand) { - SoftApConfigurationCompat.BAND_ANY -> WifiP2pConfig.GROUP_OWNER_BAND_AUTO SoftApConfigurationCompat.BAND_2GHZ -> WifiP2pConfig.GROUP_OWNER_BAND_2GHZ SoftApConfigurationCompat.BAND_5GHZ -> WifiP2pConfig.GROUP_OWNER_BAND_5GHZ - else -> throw IllegalArgumentException("Unknown band $band") + else -> { + require(SoftApConfigurationCompat.isLegacyEitherBand(band)) { "Unknown band $band" } + WifiP2pConfig.GROUP_OWNER_BAND_AUTO + } }) else -> { setGroupOperatingFrequency(SoftApConfigurationCompat.channelToFrequency(operatingBand, oc)) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt index 239d17c1..0e833300 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt @@ -192,20 +192,17 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic return SoftApConfigurationCompat( ssid = networkName, passphrase = passphrase, - band = RepeaterService.operatingBand, - channel = RepeaterService.operatingChannel, securityType = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, // is not actually used isAutoShutdownEnabled = RepeaterService.isAutoShutdownEnabled, shutdownTimeoutMillis = RepeaterService.shutdownTimeoutMillis).apply { bssid = RepeaterService.deviceAddress + setChannel(RepeaterService.operatingChannel, RepeaterService.operatingBand) } to false } } else binder?.let { binder -> val group = binder.group ?: binder.fetchPersistentGroup().let { binder.group } if (group != null) return SoftApConfigurationCompat( ssid = group.networkName, - channel = RepeaterService.operatingChannel, - band = SoftApConfigurationCompat.BAND_ANY, securityType = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, // is not actually used isAutoShutdownEnabled = RepeaterService.isAutoShutdownEnabled, shutdownTimeoutMillis = RepeaterService.shutdownTimeoutMillis).run { @@ -215,6 +212,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic holder.config = config passphrase = config.psk bssid = config.bssid + setChannel(RepeaterService.operatingChannel) this to false } catch (e: Exception) { if (e !is CancellationException) Timber.w(e) @@ -230,6 +228,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic return null } private suspend fun updateConfiguration(config: SoftApConfigurationCompat) { + config.requireSingleBand() if (RepeaterService.safeMode) { RepeaterService.networkName = config.ssid RepeaterService.deviceAddress = config.bssid diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApConfigurationCompat.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApConfigurationCompat.kt index b6ff123e..b0f62894 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApConfigurationCompat.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApConfigurationCompat.kt @@ -6,7 +6,9 @@ import android.net.MacAddress import android.net.wifi.SoftApConfiguration import android.os.Build import android.os.Parcelable +import android.util.SparseIntArray import androidx.annotation.RequiresApi +import androidx.core.os.BuildCompat import be.mygod.vpnhotspot.net.MacAddressCompat import be.mygod.vpnhotspot.net.MacAddressCompat.Companion.toCompat import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor @@ -20,9 +22,7 @@ data class SoftApConfigurationCompat( var passphrase: String? = null, var isHiddenSsid: Boolean = false, @TargetApi(23) - var band: Int = BAND_2GHZ, - @TargetApi(23) - var channel: Int = 0, + var channels: SparseIntArray = SparseIntArray(1).apply { put(BAND_2GHZ, 0) }, @TargetApi(30) var maxNumberOfClients: Int = 0, var securityType: Int = SoftApConfiguration.SECURITY_TYPE_OPEN, @@ -41,7 +41,12 @@ data class SoftApConfigurationCompat( const val BAND_2GHZ = 1 const val BAND_5GHZ = 2 const val BAND_6GHZ = 4 - const val BAND_ANY = 7 + const val BAND_60GHZ = 8 + private const val BAND_LEGACY = BAND_2GHZ or BAND_5GHZ + const val BAND_ANY = BAND_LEGACY or BAND_6GHZ + + fun isLegacyEitherBand(band: Int) = band and BAND_LEGACY == BAND_LEGACY + /** * [android.net.wifi.WifiConfiguration.KeyMgmt.WPA2_PSK] */ @@ -67,10 +72,13 @@ data class SoftApConfigurationCompat( in 1..Int.MAX_VALUE -> 5000 + chan * 5 else -> throw IllegalArgumentException("Invalid 5GHz channel $chan") } + // TODO: update for Android 12 BAND_6GHZ -> if (chan in 1..253) { 5940 + chan * 5 } else throw IllegalArgumentException("Invalid 6GHz channel $chan") - // BAND_60GHZ -> if (chan in 1 until 7) 56160 + chan * 2160 + BAND_60GHZ -> if (chan in 1 until 7) { + 56160 + chan * 2160 + } else throw IllegalArgumentException("Invalid 60GHz channel $chan") else -> throw IllegalArgumentException("Invalid band $band") } fun frequencyToChannel(freq: Int) = when (freq) { @@ -122,6 +130,10 @@ data class SoftApConfigurationCompat( private val getChannel by lazy @TargetApi(30) { SoftApConfiguration::class.java.getDeclaredMethod("getChannel") } + @get:RequiresApi(31) + private val getChannels by lazy @TargetApi(31) { + SoftApConfiguration::class.java.getDeclaredMethod("getChannels") + } @get:RequiresApi(30) private val getMaxNumberOfClients by lazy @TargetApi(30) { SoftApConfiguration::class.java.getDeclaredMethod("getMaxNumberOfClients") @@ -167,6 +179,10 @@ data class SoftApConfigurationCompat( private val setChannel by lazy { classBuilder.getDeclaredMethod("setChannel", Int::class.java, Int::class.java) } + @get:RequiresApi(31) + private val setChannels by lazy { + classBuilder.getDeclaredMethod("setChannels", SparseIntArray::class.java) + } @get:RequiresApi(30) private val setClientControlByUserEnabled by lazy { classBuilder.getDeclaredMethod("setClientControlByUserEnabled", Boolean::class.java) @@ -196,13 +212,14 @@ data class SoftApConfigurationCompat( preSharedKey, hiddenSSID, // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java;l=87;drc=aa6527cf41671d1ed417b8ebdb6b3aa614f62344 - if (Build.VERSION.SDK_INT >= 23) when (val band = apBand.getInt(this)) { - 0 -> BAND_2GHZ - 1 -> BAND_5GHZ - -1 -> BAND_2GHZ or BAND_5GHZ - else -> throw IllegalArgumentException("Unexpected band $band") - } else BAND_ANY, - if (Build.VERSION.SDK_INT >= 23) apChannel.getInt(this) else 0, + SparseIntArray(1).apply { + if (Build.VERSION.SDK_INT < 23) put(BAND_ANY, 0) else put(when (val band = apBand.getInt(this)) { + 0 -> BAND_2GHZ + 1 -> BAND_5GHZ + -1 -> BAND_LEGACY + else -> throw IllegalArgumentException("Unexpected band $band") + }, apChannel.getInt(this)) + }, 0, allowedKeyManagement.nextSetBit(0).let { selected -> require(allowedKeyManagement.nextSetBit(selected + 1) < 0) { @@ -234,8 +251,9 @@ data class SoftApConfigurationCompat( bssid?.toCompat()?.addr, passphrase, isHiddenSsid, - getBand(this) as Int, - getChannel(this) as Int, + if (BuildCompat.isAtLeastS()) getChannels(this) as SparseIntArray else SparseIntArray(1).apply { + put(getBand(this) as Int, getChannel(this) as Int) + }, getMaxNumberOfClients(this) as Int, securityType, isAutoShutdownEnabled(this) as Boolean, @@ -252,6 +270,20 @@ data class SoftApConfigurationCompat( set(value) { bssidAddr = value?.addr } + @get:Deprecated("Use channels", ReplaceWith("channels.keyAt(0)")) + @get:TargetApi(23) + val band get() = channels.keyAt(0) + @get:Deprecated("Use channels", ReplaceWith("channels.valueAt(0)")) + @get:TargetApi(23) + val channel get() = channels.valueAt(0) + fun setChannel(channel: Int, band: Int = BAND_ANY) { + channels = SparseIntArray(1).apply { put(band, channel) } + } + + /** + * Only single band/channel can be supplied on API 23-30 + */ + fun requireSingleBand() = require(channels.size() == 1) { "Unsupported number of bands configured" } /** * Based on: @@ -263,6 +295,7 @@ data class SoftApConfigurationCompat( @Deprecated("Class deprecated in framework, use toPlatform().toWifiConfiguration()") @Suppress("DEPRECATION") fun toWifiConfiguration(): android.net.wifi.WifiConfiguration { + requireSingleBand() val wc = underlying as? android.net.wifi.WifiConfiguration val result = if (wc == null) android.net.wifi.WifiConfiguration() else android.net.wifi.WifiConfiguration(wc) val original = wc?.toCompat() @@ -277,7 +310,7 @@ data class SoftApConfigurationCompat( else -> throw IllegalArgumentException("Convert fail, unsupported band setting :$band") }) apChannel.setInt(result, channel) - } else require(band == BAND_ANY) { "Specifying band is unsupported on this platform" } + } else require(isLegacyEitherBand(band)) { "Specifying band is unsupported on this platform" } if (original?.securityType != securityType) { result.allowedKeyManagement.clear() result.allowedKeyManagement.set(when (securityType) { @@ -304,7 +337,11 @@ data class SoftApConfigurationCompat( setSsid(builder, ssid) setPassphrase(builder, if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) null else passphrase, securityType) - if (channel == 0) setBand(builder, band) else setChannel(builder, channel, band) + if (BuildCompat.isAtLeastS()) setChannels(builder, channels) else { + requireSingleBand() + @Suppress("DEPRECATION") + if (channel == 0) setBand(builder, band) else setChannel(builder, channel, band) + } setBssid(builder, bssid?.toPlatform()) setMaxNumberOfClients(builder, maxNumberOfClients) setShutdownTimeoutMillis(builder, shutdownTimeoutMillis) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApDialogFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApDialogFragment.kt index be72f8f4..becf1423 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApDialogFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApDialogFragment.kt @@ -118,8 +118,7 @@ class WifiApDialogFragment : AlertDialogFragment= 23 || arg.p2pMode) { val bandOption = dialogView.band.selectedItem as BandOption - band = bandOption.band - channel = bandOption.channel + setChannel(bandOption.channel, bandOption.band) } bssid = if (dialogView.bssid.length() != 0) { MacAddressCompat.fromString(dialogView.bssid.text.toString())