Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15c7439a authored by Jaikumar Ganesh's avatar Jaikumar Ganesh
Browse files

Add TYPE_BLUETOOTH network interface for reverse tethering.

Change-Id: I2aa61ce15f57aea9e8fd3a4cb56799c8bc51e998
parent 93e7d00f
Loading
Loading
Loading
Loading
+299 −0
Original line number Diff line number Diff line
/*
 * 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 android.bluetooth;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.LinkAddress;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.net.InetAddress;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * This class tracks the data connection associated with Bluetooth
 * reverse tethering. This is a singleton class and an instance will be
 * created by ConnectivityService. BluetoothService will call into this
 * when a reverse tethered connection needs to be activated.
 *
 * @hide
 */
public class BluetoothTetheringDataTracker implements NetworkStateTracker {
    private static final String NETWORKTYPE = "BLUETOOTH_TETHER";
    private static final String TAG = "BluetoothTethering";

    private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
    private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
    private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
    private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);

    private LinkProperties mLinkProperties;
    private LinkCapabilities mLinkCapabilities;
    private NetworkInfo mNetworkInfo;

    private BluetoothPan mBluetoothPan;
    private BluetoothDevice mDevice;
    private static String mIface;

    /* For sending events to connectivity service handler */
    private Handler mCsHandler;
    private Context mContext;
    public static BluetoothTetheringDataTracker sInstance;

    private BluetoothTetheringDataTracker() {
        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORKTYPE, "");
        mLinkProperties = new LinkProperties();
        mLinkCapabilities = new LinkCapabilities();

        mNetworkInfo.setIsAvailable(false);
        setTeardownRequested(false);
    }

    public static synchronized BluetoothTetheringDataTracker getInstance() {
        if (sInstance == null) sInstance = new BluetoothTetheringDataTracker();
        return sInstance;
    }

    public Object Clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    public void setTeardownRequested(boolean isRequested) {
        mTeardownRequested.set(isRequested);
    }

    public boolean isTeardownRequested() {
        return mTeardownRequested.get();
    }

    /**
     * Begin monitoring connectivity
     */
    public void startMonitoring(Context context, Handler target) {
        mContext = context;
        mCsHandler = target;
        mBluetoothPan = new BluetoothPan(mContext);
    }

    /**
     * Disable connectivity to a network
     * TODO: do away with return value after making MobileDataStateTracker async
     */
    public boolean teardown() {
        mTeardownRequested.set(true);
        for (BluetoothDevice device: mBluetoothPan.getConnectedDevices()) {
            mBluetoothPan.disconnect(device);
        }
        return true;
    }

    /**
     * Re-enable connectivity to a network after a {@link #teardown()}.
     */
    public boolean reconnect() {
        mTeardownRequested.set(false);
        //Ignore
        return true;
    }

    /**
     * Turn the wireless radio off for a network.
     * @param turnOn {@code true} to turn the radio on, {@code false}
     */
    public boolean setRadio(boolean turnOn) {
        return true;
    }

    /**
     * @return true - If are we currently tethered with another device.
     */
    public synchronized boolean isAvailable() {
        return mNetworkInfo.isAvailable();
    }

    /**
     * Tells the underlying networking system that the caller wants to
     * begin using the named feature. The interpretation of {@code feature}
     * is completely up to each networking implementation.
     * @param feature the name of the feature to be used
     * @param callingPid the process ID of the process that is issuing this request
     * @param callingUid the user ID of the process that is issuing this request
     * @return an integer value representing the outcome of the request.
     * The interpretation of this value is specific to each networking
     * implementation+feature combination, except that the value {@code -1}
     * always indicates failure.
     * TODO: needs to go away
     */
    public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
        return -1;
    }

    /**
     * Tells the underlying networking system that the caller is finished
     * using the named feature. The interpretation of {@code feature}
     * is completely up to each networking implementation.
     * @param feature the name of the feature that is no longer needed.
     * @param callingPid the process ID of the process that is issuing this request
     * @param callingUid the user ID of the process that is issuing this request
     * @return an integer value representing the outcome of the request.
     * The interpretation of this value is specific to each networking
     * implementation+feature combination, except that the value {@code -1}
     * always indicates failure.
     * TODO: needs to go away
     */
    public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
        return -1;
    }

    /**
     * @param enabled
     */
    public void setDataEnable(boolean enabled) {
        android.util.Log.d(TAG, "setDataEnabled: IGNORING enabled=" + enabled);
    }

    /**
     * Check if private DNS route is set for the network
     */
    public boolean isPrivateDnsRouteSet() {
        return mPrivateDnsRouteSet.get();
    }

    /**
     * Set a flag indicating private DNS route is set
     */
    public void privateDnsRouteSet(boolean enabled) {
        mPrivateDnsRouteSet.set(enabled);
    }

    /**
     * Fetch NetworkInfo for the network
     */
    public synchronized NetworkInfo getNetworkInfo() {
        return mNetworkInfo;
    }

    /**
     * Fetch LinkProperties for the network
     */
    public synchronized LinkProperties getLinkProperties() {
        return new LinkProperties(mLinkProperties);
    }

   /**
     * A capability is an Integer/String pair, the capabilities
     * are defined in the class LinkSocket#Key.
     *
     * @return a copy of this connections capabilities, may be empty but never null.
     */
    public LinkCapabilities getLinkCapabilities() {
        return new LinkCapabilities(mLinkCapabilities);
    }

    /**
     * Fetch default gateway address for the network
     */
    public int getDefaultGatewayAddr() {
        return mDefaultGatewayAddr.get();
    }

    /**
     * Check if default route is set
     */
    public boolean isDefaultRouteSet() {
        return mDefaultRouteSet.get();
    }

    /**
     * Set a flag indicating default route is set for the network
     */
    public void defaultRouteSet(boolean enabled) {
        mDefaultRouteSet.set(enabled);
    }

    /**
     * Return the system properties name associated with the tcp buffer sizes
     * for this network.
     */
    public String getTcpBufferSizesPropName() {
        return "net.tcp.buffersize.wifi";
    }


    public synchronized void startReverseTether(String iface, BluetoothDevice device) {
        mIface = iface;
        mDevice = device;
        Thread dhcpThread = new Thread(new Runnable() {
            public void run() {
                //TODO(): Add callbacks for failure and success case.
                //Currently this thread runs independently.
                DhcpInfo dhcpInfo = new DhcpInfo();
                if (!NetworkUtils.runDhcp(mIface, dhcpInfo)) {
                    Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
                    return;
                }
                mLinkProperties.addLinkAddress(new LinkAddress(
                    NetworkUtils.intToInetAddress(dhcpInfo.ipAddress),
                    NetworkUtils.intToInetAddress(dhcpInfo.netmask)));
                mLinkProperties.setGateway(NetworkUtils.intToInetAddress(dhcpInfo.gateway));
                InetAddress dns1Addr = NetworkUtils.intToInetAddress(dhcpInfo.dns1);
                if (dns1Addr == null || dns1Addr.equals("0.0.0.0")) {
                    mLinkProperties.addDns(dns1Addr);
                }
                InetAddress dns2Addr = NetworkUtils.intToInetAddress(dhcpInfo.dns2);
                if (dns2Addr == null || dns2Addr.equals("0.0.0.0")) {
                    mLinkProperties.addDns(dns2Addr);
                }
                mLinkProperties.setInterfaceName(mIface);

                mNetworkInfo.setIsAvailable(true);
                mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);

                Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
                msg.sendToTarget();

                msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
                msg.sendToTarget();
            }
        });
        dhcpThread.start();
    }

    public synchronized void stopReverseTether(String iface) {
        NetworkUtils.stopDhcp(iface);

        mLinkProperties.clear();
        mNetworkInfo.setIsAvailable(false);
        mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);

        Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
        msg.sendToTarget();

        msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
        msg.sendToTarget();
    }
}
+8 −2
Original line number Diff line number Diff line
@@ -213,10 +213,16 @@ public class ConnectivityManager
     */
    public static final int TYPE_WIMAX       = 6;

    /**
     * Bluetooth data connection. This is used for Bluetooth reverse tethering.
     * @hide
     */
    public static final int TYPE_BLUETOOTH   = 7;

    /** {@hide} */
    public static final int TYPE_DUMMY       = 7;
    public static final int TYPE_DUMMY       = 8;
    /** {@hide} TODO: Need to adjust this for WiMAX. */
    public static final int MAX_RADIO_TYPE   = TYPE_WIFI;
    public static final int MAX_RADIO_TYPE   = TYPE_DUMMY;
    /** {@hide} TODO: Need to adjust this for WiMAX. */
    public static final int MAX_NETWORK_TYPE = TYPE_DUMMY;

+6 −5
Original line number Diff line number Diff line
@@ -16,8 +16,7 @@

package com.android.server;

import android.app.Notification;
import android.app.NotificationManager;
import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -26,9 +25,9 @@ import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.DummyDataStateTracker;
import android.net.IConnectivityManager;
import android.net.LinkProperties;
import android.net.MobileDataStateTracker;
import android.net.NetworkInfo;
import android.net.LinkProperties;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
import android.net.Proxy;
@@ -50,7 +49,6 @@ import android.util.EventLog;
import android.util.Slog;

import com.android.internal.telephony.Phone;

import com.android.server.connectivity.Tethering;

import java.io.FileDescriptor;
@@ -58,7 +56,6 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
@@ -412,6 +409,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                        mNetAttributes[netType].mName);
                mNetTrackers[netType].startMonitoring(context, mHandler);
                break;
            case ConnectivityManager.TYPE_BLUETOOTH:
                mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
                mNetTrackers[netType].startMonitoring(context, mHandler);
                break;
            default:
                loge("Trying to create a DataStateTracker for an unknown radio type " +
                        mNetAttributes[netType].mRadio);