Various bugfix for Wi-Fi direct mode
This commit is contained in:
@@ -63,23 +63,11 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
|||||||
val service get() = this@HotspotService
|
val service get() = this@HotspotService
|
||||||
var data: MainActivity.Data? = null
|
var data: MainActivity.Data? = null
|
||||||
|
|
||||||
fun shutdown() {
|
fun shutdown() = when (status) {
|
||||||
when (status) {
|
Status.ACTIVE_P2P -> removeGroup()
|
||||||
Status.ACTIVE_P2P -> p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener {
|
|
||||||
override fun onSuccess() = clean()
|
|
||||||
override fun onFailure(reason: Int) {
|
|
||||||
if (reason == WifiP2pManager.BUSY) clean() else { // assuming it's already gone
|
|
||||||
Toast.makeText(this@HotspotService, "Failed to remove P2P group (${formatReason(reason)})",
|
|
||||||
Toast.LENGTH_SHORT).show()
|
|
||||||
LocalBroadcastManager.getInstance(this@HotspotService)
|
|
||||||
.sendBroadcast(Intent(STATUS_CHANGED))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
else -> clean()
|
else -> clean()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private val wifiManager by lazy { getSystemService(Context.WIFI_SERVICE) as WifiManager }
|
private val wifiManager by lazy { getSystemService(Context.WIFI_SERVICE) as WifiManager }
|
||||||
private val p2pManager by lazy { getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager }
|
private val p2pManager by lazy { getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager }
|
||||||
@@ -199,10 +187,10 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
|||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startFailure(msg: String) {
|
private fun startFailure(msg: String, group: WifiP2pGroup? = null) {
|
||||||
Toast.makeText(this@HotspotService, msg, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this@HotspotService, msg, Toast.LENGTH_SHORT).show()
|
||||||
showNotification()
|
showNotification()
|
||||||
clean()
|
if (group != null) removeGroup() else clean()
|
||||||
}
|
}
|
||||||
private fun doStart() = p2pManager.createGroup(channel, object : WifiP2pManager.ActionListener {
|
private fun doStart() = p2pManager.createGroup(channel, object : WifiP2pManager.ActionListener {
|
||||||
override fun onFailure(reason: Int) = startFailure("Failed to create P2P group (${formatReason(reason)})")
|
override fun onFailure(reason: Int) = startFailure("Failed to create P2P group (${formatReason(reason)})")
|
||||||
@@ -234,15 +222,28 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
|||||||
val routing = try {
|
val routing = try {
|
||||||
Routing(upstream, downstream, owner)
|
Routing(upstream, downstream, owner)
|
||||||
} catch (_: Routing.InterfaceNotFoundException) {
|
} catch (_: Routing.InterfaceNotFoundException) {
|
||||||
startFailure(getString(R.string.exception_interface_not_found))
|
startFailure(getString(R.string.exception_interface_not_found), group)
|
||||||
return
|
return
|
||||||
}.p2pRule().forward().dnsRedirect(dns)
|
}.p2pRule().forward().dnsRedirect(dns)
|
||||||
if (routing.start()) {
|
if (routing.start()) {
|
||||||
this.routing = routing
|
this.routing = routing
|
||||||
doStart(group)
|
doStart(group)
|
||||||
} else startFailure("Something went wrong, please check logcat.")
|
} else startFailure("Something went wrong, please check logcat.", group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun removeGroup() {
|
||||||
|
p2pManager.removeGroup(channel, object : WifiP2pManager.ActionListener {
|
||||||
|
override fun onSuccess() = clean()
|
||||||
|
override fun onFailure(reason: Int) {
|
||||||
|
if (reason == WifiP2pManager.BUSY) clean() else { // assuming it's already gone
|
||||||
|
Toast.makeText(this@HotspotService, "Failed to remove P2P group (${formatReason(reason)})",
|
||||||
|
Toast.LENGTH_SHORT).show()
|
||||||
|
status = Status.ACTIVE_P2P
|
||||||
|
LocalBroadcastManager.getInstance(this@HotspotService).sendBroadcast(Intent(STATUS_CHANGED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
private fun unregisterReceiver() {
|
private fun unregisterReceiver() {
|
||||||
if (receiverRegistered) {
|
if (receiverRegistered) {
|
||||||
unregisterReceiver(receiver)
|
unregisterReceiver(receiver)
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class MainActivity : AppCompatActivity(), ServiceConnection, Toolbar.OnMenuItemC
|
|||||||
}
|
}
|
||||||
holder.binding.device = device
|
holder.binding.device = device
|
||||||
holder.binding.ipAddress = when (position) {
|
holder.binding.ipAddress = when (position) {
|
||||||
0 -> binder?.service?.routing?.hostAddress
|
0 -> binder?.service?.routing?.hostAddress?.hostAddress
|
||||||
else -> arpCache[device?.deviceAddress]
|
else -> arpCache[device?.deviceAddress]
|
||||||
}
|
}
|
||||||
holder.binding.executePendingBindings()
|
holder.binding.executePendingBindings()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class Routing(private val upstream: String, val downstream: String, ownerAddress
|
|||||||
|
|
||||||
class InterfaceNotFoundException : IOException()
|
class InterfaceNotFoundException : IOException()
|
||||||
|
|
||||||
val hostAddress: String
|
val hostAddress: InetAddress
|
||||||
private val subnetPrefixLength: Short
|
private val subnetPrefixLength: Short
|
||||||
private val startScript = LinkedList<String>()
|
private val startScript = LinkedList<String>()
|
||||||
private val stopScript = LinkedList<String>()
|
private val stopScript = LinkedList<String>()
|
||||||
@@ -28,19 +28,28 @@ class Routing(private val upstream: String, val downstream: String, ownerAddress
|
|||||||
val address = NetworkInterface.getByName(downstream)?.interfaceAddresses
|
val address = NetworkInterface.getByName(downstream)?.interfaceAddresses
|
||||||
?.singleOrNull { if (ownerAddress == null) it.address is Inet4Address else it.address == ownerAddress }
|
?.singleOrNull { if (ownerAddress == null) it.address is Inet4Address else it.address == ownerAddress }
|
||||||
?: throw InterfaceNotFoundException()
|
?: throw InterfaceNotFoundException()
|
||||||
hostAddress = address.address.hostAddress
|
hostAddress = address.address
|
||||||
subnetPrefixLength = address.networkPrefixLength
|
subnetPrefixLength = address.networkPrefixLength
|
||||||
}
|
}
|
||||||
|
|
||||||
fun p2pRule(): Routing {
|
fun p2pRule(): Routing {
|
||||||
|
// clear suffix bits
|
||||||
|
val address = hostAddress.address
|
||||||
|
var done = subnetPrefixLength.toInt()
|
||||||
|
while (done < address.size shl 3) {
|
||||||
|
val index = done shr 3
|
||||||
|
address[index] = (address[index].toInt() and (0x7f00 shr (done and 7))).toByte()
|
||||||
|
done = (index + 1) shl 3
|
||||||
|
}
|
||||||
|
val hostAddress = InetAddress.getByAddress(address).hostAddress
|
||||||
startScript.add("echo 1 >/proc/sys/net/ipv4/ip_forward") // Wi-Fi direct doesn't enable ip_forward
|
startScript.add("echo 1 >/proc/sys/net/ipv4/ip_forward") // Wi-Fi direct doesn't enable ip_forward
|
||||||
startScript.add("ip route add default dev $upstream scope link table 62")
|
startScript.add("ip route add default dev $upstream scope link table 62")
|
||||||
startScript.add("ip route add $hostAddress/$subnetPrefixLength dev $downstream scope link table 62")
|
startScript.add("ip route add $hostAddress/$subnetPrefixLength dev $downstream scope link table 62")
|
||||||
startScript.add("ip route add broadcast 255.255.255.255 dev $downstream scope link table 62")
|
startScript.add("ip route add broadcast 255.255.255.255 dev $downstream scope link table 62")
|
||||||
startScript.add("ip rule add iif $downstream lookup 62")
|
startScript.add("ip rule add iif $downstream lookup 62")
|
||||||
stopScript.addFirst("ip route del default dev $upstream scope link table 62")
|
stopScript.addFirst("ip route del default dev $upstream scope link table 62")
|
||||||
stopScript.addFirst("ip route del $hostAddress/$subnetPrefixLength dev $downstream scope link table 62")
|
// removing each rule may fail if downstream is already removed
|
||||||
stopScript.addFirst("ip route del broadcast 255.255.255.255 dev $downstream scope link table 62")
|
stopScript.addFirst("ip route flush table 62")
|
||||||
stopScript.addFirst("ip rule del iif $downstream lookup 62")
|
stopScript.addFirst("ip rule del iif $downstream lookup 62")
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@@ -65,6 +74,7 @@ class Routing(private val upstream: String, val downstream: String, ownerAddress
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun dnsRedirect(dns: String): Routing {
|
fun dnsRedirect(dns: String): Routing {
|
||||||
|
val hostAddress = hostAddress.hostAddress
|
||||||
startScript.add("iptables -t nat -A PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
startScript.add("iptables -t nat -A PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
||||||
startScript.add("iptables -t nat -A PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
startScript.add("iptables -t nat -A PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
||||||
stopScript.addFirst("iptables -t nat -D PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
stopScript.addFirst("iptables -t nat -D PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ fun Bundle.put(key: String, map: Array<String>): Bundle {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
const val NOISYSU_TAG = "NoisySU"
|
private const val NOISYSU_TAG = "NoisySU"
|
||||||
const val NOISYSU_SUFFIX = "SUCCESS\n"
|
private const val NOISYSU_SUFFIX = "SUCCESS\n"
|
||||||
fun loggerSuStream(command: String): InputStream {
|
fun loggerSuStream(command: String): InputStream {
|
||||||
val process = ProcessBuilder("su", "-c", command)
|
val process = ProcessBuilder("su", "-c", command)
|
||||||
.redirectErrorStream(true)
|
.redirectErrorStream(true)
|
||||||
|
|||||||
Reference in New Issue
Block a user