aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java')
-rw-r--r--app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java581
1 files changed, 581 insertions, 0 deletions
diff --git a/app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java b/app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java
new file mode 100644
index 0000000..bab5c5d
--- /dev/null
+++ b/app/src/fil/libre/repwifiapp/fwproxies/RepWifiNetworkAgent.java
@@ -0,0 +1,581 @@
+//
+// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net>
+//
+// This file is part of RepWifiApp.
+//
+// RepWifiApp is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// RepWifiApp is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with RepWifiApp. If not, see <http://www.gnu.org/licenses/>.
+//
+// ********************************************************************
+//
+// This file is derivative work, inspired by the original class definition:
+// "com.android.server.wifi.WifiStateMachine$WifiNetworkAgent.java"
+// as found in version 6.0 of the Android Operating System.
+// Following is the original copyright notice:
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package fil.libre.repwifiapp.fwproxies;
+
+import android.content.Context;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.util.Log;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class RepWifiNetworkAgent extends Handler {
+
+ public final int netId;
+
+ private Messenger myMessenger = null;
+
+ private volatile AsyncChannelProxy mAsyncChannel;
+ private final String LOG_TAG;
+ private static final boolean DBG = true;
+ private static final boolean VDBG = true;
+ private final Context mContext;
+ private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>();
+ private volatile long mLastBwRefreshTime = 0;
+ private static final long BW_REFRESH_MIN_WIN_MS = 500;
+ private boolean mPollLceScheduled = false;
+ private AtomicBoolean mPollLcePending = new AtomicBoolean(false);
+
+ /* as in com.android.internal.util.Protocol.BASE_NETWORK_AGENT; */
+ private static final int BASE = 0x00081000;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform it of
+ * suspected connectivity problems on its network. The NetworkAgent
+ * should take steps to verify and correct connectivity.
+ */
+ public static final int CMD_SUSPECT_BAD = BASE;
+
+ /**
+ * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
+ * ConnectivityService to pass the current NetworkInfo (connection state).
+ * Sent when the NetworkInfo changes, mainly due to change of state.
+ * obj = NetworkInfo
+ */
+ public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * NetworkCapabilties.
+ * obj = NetworkCapabilities
+ */
+ public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * NetworkProperties.
+ * obj = NetworkProperties
+ */
+ public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
+
+ public static final int WIFI_BASE_SCORE = 60;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * network score.
+ * obj = network score Integer
+ */
+ public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to add new UID ranges
+ * to be forced into this Network. For VPNs only.
+ * obj = UidRange[] to forward
+ */
+ public static final int EVENT_UID_RANGES_ADDED = BASE + 5;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to remove UID ranges
+ * from being forced into this Network. For VPNs only.
+ * obj = UidRange[] to stop forwarding
+ */
+ public static final int EVENT_UID_RANGES_REMOVED = BASE + 6;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform the agent of
+ * the
+ * networks status - whether we could use the network or could not, due to
+ * either a bad network configuration (no internet link) or captive portal.
+ *
+ * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK}
+ */
+ public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
+
+ public static final int VALID_NETWORK = 1;
+ public static final int INVALID_NETWORK = 2;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to indicate this network
+ * was
+ * explicitly selected. This should be sent before the NetworkInfo is marked
+ * CONNECTED so it can be given special treatment at that time.
+ *
+ * obj = boolean indicating whether to use this network even if unvalidated
+ */
+ public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform the agent of
+ * whether the network should in the future be used even if not validated.
+ * This decision is made by the user, but it is the network transport's
+ * responsibility to remember it.
+ *
+ * arg1 = 1 if true, 0 if false
+ */
+ public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to inform the agent to
+ * pull
+ * the underlying network connection for updated bandwidth information.
+ */
+ public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10;
+
+ /**
+ * Sent by ConnectivityService to the NetworkAgent to request that the
+ * specified packet be sent
+ * periodically on the given interval.
+ *
+ * arg1 = the slot number of the keepalive to start
+ * arg2 = interval in seconds
+ * obj = KeepalivePacketData object describing the data to be sent
+ *
+ * Also used internally by ConnectivityService / KeepaliveTracker, with
+ * different semantics.
+ */
+ public static final int CMD_START_PACKET_KEEPALIVE = BASE + 11;
+
+ /**
+ * Requests that the specified keepalive packet be stopped.
+ *
+ * arg1 = slot number of the keepalive to stop.
+ *
+ * Also used internally by ConnectivityService / KeepaliveTracker, with
+ * different semantics.
+ */
+ public static final int CMD_STOP_PACKET_KEEPALIVE = BASE + 12;
+
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to provide status on a
+ * packet keepalive
+ * request. This may either be the reply to a CMD_START_PACKET_KEEPALIVE, or
+ * an asynchronous
+ * error notification.
+ *
+ * This is also sent by KeepaliveTracker to the app's
+ * ConnectivityManager.PacketKeepalive to
+ * so that the app's PacketKeepaliveCallback methods can be called.
+ *
+ * arg1 = slot number of the keepalive
+ * arg2 = error code
+ */
+ public static final int EVENT_PACKET_KEEPALIVE = BASE + 13;
+
+ /**
+ * Sent by ConnectivityService to inform this network transport of signal
+ * strength thresholds
+ * that when crossed should trigger a system wakeup and a
+ * NetworkCapabilities update.
+ *
+ * obj = int[] describing signal strength thresholds.
+ */
+ public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14;
+
+ /**
+ * Sent by ConnectivityService to the NeworkAgent to inform the agent to
+ * avoid
+ * automatically reconnecting to this network (e.g. via autojoin). Happens
+ * when user selects "No" option on the "Stay connected?" dialog box.
+ */
+ public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
+
+ public RepWifiNetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
+ NetworkCapabilitiesProxy nc, LinkPropertiesProxy lp, int score) {
+
+ super(looper);
+
+ LOG_TAG = logTag;
+ mContext = context;
+ if (ni == null || nc == null || lp == null) {
+ throw new IllegalArgumentException();
+ }
+
+ if (VDBG)
+ log("Registering NetworkAgent");
+
+ ConnectivityManagerProxy cm = new ConnectivityManagerProxy(mContext);
+
+ myMessenger = new Messenger(this);
+ netId = cm.registerNetworkAgent(myMessenger, new NetworkInfoProxy(ni),
+ new LinkPropertiesProxy(lp), new NetworkCapabilitiesProxy(nc), score);
+
+ }
+
+ public boolean isChannellConnected() {
+ return (mAsyncChannel != null);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+
+ switch (msg.what) {
+ case AsyncChannelProxy.CMD_CHANNEL_FULL_CONNECTION: {
+ if (mAsyncChannel != null) {
+ log("Received new connection while already connected!");
+ } else {
+ if (VDBG)
+ log("NetworkAgent fully connected");
+ AsyncChannelProxy ac = new AsyncChannelProxy();
+ ac.connected(null, this, msg.replyTo);
+ ac.replyToMessage(msg, AsyncChannelProxy.CMD_CHANNEL_FULLY_CONNECTED,
+ AsyncChannelProxy.STATUS_SUCCESSFUL);
+ synchronized (mPreConnectedQueue) {
+ mAsyncChannel = ac;
+ for (Message m : mPreConnectedQueue) {
+ ac.sendMessage(m);
+ }
+ mPreConnectedQueue.clear();
+ }
+ }
+ break;
+ }
+ case AsyncChannelProxy.CMD_CHANNEL_DISCONNECT: {
+ if (VDBG)
+ log("CMD_CHANNEL_DISCONNECT");
+ if (mAsyncChannel != null)
+ mAsyncChannel.disconnect();
+ break;
+ }
+ case AsyncChannelProxy.CMD_CHANNEL_DISCONNECTED: {
+ if (DBG)
+ log("NetworkAgent channel lost");
+ // let the client know CS is done with us.
+
+ synchronized (mPreConnectedQueue) {
+ mAsyncChannel = null;
+ }
+ break;
+ }
+ case CMD_SUSPECT_BAD: {
+ log("Unhandled Message " + msg);
+ break;
+ }
+ case CMD_REQUEST_BANDWIDTH_UPDATE: {
+ long currentTimeMs = System.currentTimeMillis();
+ if (VDBG) {
+ log("CMD_REQUEST_BANDWIDTH_UPDATE request received.");
+ }
+ if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
+ mPollLceScheduled = false;
+ if (mPollLcePending.getAndSet(true) == false) {
+
+ shouldCallUninimplementedMethod("pollLceData()");
+
+ }
+ } else {
+ // deliver the request at a later time rather than discard it
+ // completely.
+ if (!mPollLceScheduled) {
+ long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS - currentTimeMs + 1;
+ mPollLceScheduled = sendEmptyMessageDelayed(CMD_REQUEST_BANDWIDTH_UPDATE,
+ waitTime);
+ }
+ }
+ break;
+ }
+ case CMD_REPORT_NETWORK_STATUS: {
+ if (VDBG) {
+ log("CMD_REPORT_NETWORK_STATUS("
+ + (msg.arg1 == VALID_NETWORK ? "VALID)" : "INVALID)"));
+ }
+ shouldCallUninimplementedMethod("shounetworkStatus(msg.arg1)");
+ break;
+ }
+ case CMD_SAVE_ACCEPT_UNVALIDATED: {
+ shouldCallUninimplementedMethod("saveAcceptUnvalidated(msg.arg1 != 0)");
+
+ break;
+ }
+ case CMD_START_PACKET_KEEPALIVE: {
+ shouldCallUninimplementedMethod("startPacketKeepalive(msg)");
+ break;
+ }
+ case CMD_STOP_PACKET_KEEPALIVE: {
+ shouldCallUninimplementedMethod("stopPacketKeepalive(msg)");
+
+ break;
+ }
+
+ case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: {
+ ArrayList<Integer> thresholds = ((Bundle) msg.obj).getIntegerArrayList("thresholds");
+ int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0];
+ for (int i = 0; i < intThresholds.length; i++) {
+ intThresholds[i] = thresholds.get(i);
+ }
+ shouldCallUninimplementedMethod("setSignalStrengthThresholds(intThresholds)");
+ break;
+ }
+ case CMD_PREVENT_AUTOMATIC_RECONNECT: {
+ shouldCallUninimplementedMethod("preventAutomaticReconnect()");
+ break;
+ }
+ default: {
+ String rep = "";
+ if (msg.replyTo != null) {
+ rep = msg.replyTo.toString();
+ }
+ log("Received unhandled message: what = " + msg.what + " replyTo: " + rep);
+ }
+ }
+ }
+
+ private void queueOrSendMessage(int what, Object obj) {
+ queueOrSendMessage(what, 0, 0, obj);
+ }
+
+ /*
+ * private void queueOrSendMessage(int what, int arg1, int arg2) {
+ * queueOrSendMessage(what, arg1, arg2, null);
+ * }
+ */
+
+ private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) {
+ if (VDBG)
+ log("Send or queue message; what=" + what);
+ Message msg = Message.obtain();
+ msg.what = what;
+ msg.arg1 = arg1;
+ msg.arg2 = arg2;
+ msg.obj = obj;
+ msg.replyTo = this.myMessenger;
+
+ queueOrSendMessage(msg);
+ }
+
+ private void queueOrSendMessage(Message msg) {
+ synchronized (mPreConnectedQueue) {
+ if (mAsyncChannel != null) {
+ if (VDBG)
+ log("Actually sending message " + msg);
+ mAsyncChannel.sendMessage(msg);
+ } else {
+ mPreConnectedQueue.add(msg);
+ }
+ }
+ }
+
+ /**
+ * Called by the bearer code when it has new LinkProperties data.
+ */
+ public void sendLinkProperties(LinkPropertiesProxy linkProperties) {
+ queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED,
+ new LinkPropertiesProxy(linkProperties).inner);
+ }
+
+ /**
+ * Called by the bearer code when it has new NetworkInfo data.
+ */
+ public void sendNetworkInfo(NetworkInfo networkInfo) {
+ queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED,
+ new NetworkInfoProxy(networkInfo).getNetworkInfo());
+ }
+
+ /**
+ * Called by the bearer code when it has new NetworkCapabilities data.
+ */
+ public void sendNetworkCapabilities(NetworkCapabilitiesProxy networkCapabilities) {
+ mPollLcePending.set(false);
+ mLastBwRefreshTime = System.currentTimeMillis();
+ queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, new NetworkCapabilitiesProxy(
+ networkCapabilities).inner);
+ }
+
+ /**
+ * Called by the bearer code when it has a new score for this network.
+ */
+ public void sendNetworkScore(int score) {
+ if (score < 0) {
+ throw new IllegalArgumentException("Score must be >= 0");
+ }
+ queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, Integer.valueOf(score));
+ }
+
+ protected void log(String s) {
+ Log.d(LOG_TAG, "NetworkAgent: " + s);
+ }
+
+ private void shouldCallUninimplementedMethod(String methodName) {
+ String msg = "[WRN] Should be calling " + methodName
+ + " but the method is not implemented by the proxy..";
+ Log.w(LOG_TAG, msg);
+ }
+
+ /*
+ * A proxy for package com.android.internal.util.AsyncChannel;
+ * Mererly replicates constants and functions needed by the NetworkAgent to
+ * communicate with the other side of the Handler
+ */
+ private static class AsyncChannelProxy extends FrameworkProxy {
+
+ // as in com.android.internal.util.Protocol.BASE_SYSTEM_ASYNC_CHANNEL;
+ private static final int BASE = 0x00011000;
+
+ /** Successful status always 0, !0 is an unsuccessful status */
+ public static final int STATUS_SUCCESSFUL = 0;
+
+ /**
+ * Command typically sent when after receiving the
+ * CMD_CHANNEL_HALF_CONNECTED.
+ * This is used to initiate a long term connection with the destination
+ * and
+ * typically the destination will reply with
+ * CMD_CHANNEL_FULLY_CONNECTED.
+ *
+ * msg.replyTo = srcMessenger.
+ */
+ public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1;
+
+ /**
+ * Command typically sent after the destination receives a
+ * CMD_CHANNEL_FULL_CONNECTION.
+ * This signifies the acceptance or rejection of the channel by the
+ * sender.
+ *
+ * msg.arg1 == 0 : Accept connection
+ * : All other values signify the destination rejected the connection
+ * and {@link AsyncChannel#disconnect} would typically be called.
+ */
+ public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2;
+
+ /**
+ * Command sent when one side or the other wishes to disconnect. The
+ * sender
+ * may or may not be able to receive a reply depending upon the protocol
+ * and
+ * the state of the connection. The receiver should call
+ * {@link AsyncChannel#disconnect} to close its side of the channel and
+ * it will receive a CMD_CHANNEL_DISCONNECTED
+ * when the channel is closed.
+ *
+ * msg.replyTo = messenger that is disconnecting
+ */
+ public static final int CMD_CHANNEL_DISCONNECT = BASE + 3;
+
+ /**
+ * Command sent when the channel becomes disconnected. This is sent when
+ * the
+ * channel is forcibly disconnected by the system or as a reply to
+ * CMD_CHANNEL_DISCONNECT.
+ *
+ * msg.arg1 == 0 : STATUS_SUCCESSFUL
+ * 1 : STATUS_BINDING_UNSUCCESSFUL
+ * 2 : STATUS_SEND_UNSUCCESSFUL
+ * : All other values signify failure and the channel state is
+ * indeterminate
+ * msg.obj == the AsyncChannel
+ * msg.replyTo = messenger disconnecting or null if it was never
+ * connected.
+ */
+ public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4;
+
+ /*
+ * Following is a block of unused system constants, kept here for future
+ * reference
+ *//**
+ * Command sent when the channel is half connected. Half connected
+ * means that the channel can be used to send commends to the
+ * destination
+ * but the destination is unaware that the channel exists. The first
+ * command sent to the destination is typically
+ * CMD_CHANNEL_FULL_CONNECTION if
+ * it is desired to establish a long term connection, but any command
+ * maybe
+ * sent.
+ *
+ * msg.arg1 == 0 : STATUS_SUCCESSFUL
+ * 1 : STATUS_BINDING_UNSUCCESSFUL
+ * msg.obj == the AsyncChannel
+ * msg.replyTo == dstMessenger if successful
+ */
+ /*
+ * public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0;
+ *
+ * private static final int CMD_TO_STRING_COUNT =
+ * CMD_CHANNEL_DISCONNECTED - BASE + 1;
+ *//** Error attempting to bind on a connect */
+ /*
+ * public static final int STATUS_BINDING_UNSUCCESSFUL = 1;
+ *//** Error attempting to send a message */
+ /*
+ * public static final int STATUS_SEND_UNSUCCESSFUL = 2;
+ *//** CMD_FULLY_CONNECTED refused because a connection already exists */
+ /*
+ * public static final int
+ * STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3;
+ *//** Error indicating abnormal termination of destination messenger */
+ /*
+ * public static final int STATUS_REMOTE_DISCONNECTION = 4;
+ */
+
+ public AsyncChannelProxy() {
+ createInnerObject(null);
+ }
+
+ @Override
+ protected String getInnerClassName() {
+ return "com.android.internal.util.AsyncChannel";
+ }
+
+ public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
+ invokeMethod("connected", getTypesArray(Context.class, Handler.class, Messenger.class),
+ srcContext, srcHandler, dstMessenger);
+ }
+
+ public void disconnect() {
+ invokeMethod("disconnect", null);
+ }
+
+ public void sendMessage(Message msg) {
+ invokeMethod("sendMessage", Message.class, msg);
+ }
+
+ public void replyToMessage(Message srcMsg, int what, int arg1) {
+ invokeMethod("replyToMessage", getTypesArray(Message.class, int.class, int.class),
+ srcMsg, what, arg1);
+ }
+
+ }
+
+}