1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.pan;
18 
19 import android.bluetooth.BluetoothDevice;
20 import android.content.Context;
21 import android.net.ConnectivityManager;
22 import android.net.DhcpResults;
23 import android.net.LinkProperties;
24 import android.net.NetworkAgent;
25 import android.net.NetworkCapabilities;
26 import android.net.NetworkFactory;
27 import android.net.NetworkInfo;
28 import android.net.NetworkInfo.DetailedState;
29 import android.net.NetworkRequest;
30 import android.net.ip.IpManager;
31 import android.net.ip.IpManager.WaitForProvisioningCallback;
32 import android.os.Looper;
33 import android.os.Message;
34 import android.os.Messenger;
35 import android.os.RemoteException;
36 import android.text.TextUtils;
37 import android.util.Slog;
38 
39 import com.android.bluetooth.pan.PanService;
40 import com.android.internal.util.AsyncChannel;
41 
42 /**
43  * This class tracks the data connection associated with Bluetooth
44  * reverse tethering. PanService calls it when a reverse tethered
45  * connection needs to be activated or deactivated.
46  *
47  * @hide
48  */
49 public class BluetoothTetheringNetworkFactory extends NetworkFactory {
50     private static final String NETWORK_TYPE = "Bluetooth Tethering";
51     private static final String TAG = "BluetoothTetheringNetworkFactory";
52     private static final int NETWORK_SCORE = 69;
53 
54     private final NetworkCapabilities mNetworkCapabilities;
55     private final Context mContext;
56     private final PanService mPanService;
57 
58     // All accesses to these must be synchronized(this).
59     private final NetworkInfo mNetworkInfo;
60     private IpManager mIpManager;
61     private String mInterfaceName;
62     private NetworkAgent mNetworkAgent;
63 
BluetoothTetheringNetworkFactory(Context context, Looper looper, PanService panService)64     public BluetoothTetheringNetworkFactory(Context context, Looper looper, PanService panService) {
65         super(looper, context, NETWORK_TYPE, new NetworkCapabilities());
66 
67         mContext = context;
68         mPanService = panService;
69 
70         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORK_TYPE, "");
71         mNetworkCapabilities = new NetworkCapabilities();
72         initNetworkCapabilities();
73         setCapabilityFilter(mNetworkCapabilities);
74     }
75 
stopIpManagerLocked()76     private void stopIpManagerLocked() {
77         if (mIpManager != null) {
78             mIpManager.shutdown();
79             mIpManager = null;
80         }
81     }
82 
83     // Called by NetworkFactory when PanService and NetworkFactory both desire a Bluetooth
84     // reverse-tether connection.  A network interface for Bluetooth reverse-tethering can be
85     // assumed to be available because we only register our NetworkFactory when it is so.
86     @Override
startNetwork()87     protected void startNetwork() {
88         // TODO: Figure out how to replace this thread with simple invocations
89         // of IpManager. This will likely necessitate a rethink about
90         // NetworkAgent, NetworkInfo, and associated instance lifetimes.
91         Thread ipProvisioningThread = new Thread(new Runnable() {
92             public void run() {
93                 LinkProperties linkProperties;
94                 final WaitForProvisioningCallback ipmCallback = new WaitForProvisioningCallback() {
95                     @Override
96                     public void onLinkPropertiesChange(LinkProperties newLp) {
97                         synchronized (BluetoothTetheringNetworkFactory.this) {
98                             if (mNetworkAgent != null && mNetworkInfo.isConnected()) {
99                                 mNetworkAgent.sendLinkProperties(newLp);
100                             }
101                         }
102                     }
103                 };
104 
105                 synchronized (BluetoothTetheringNetworkFactory.this) {
106                     if (TextUtils.isEmpty(mInterfaceName)) {
107                         Slog.e(TAG, "attempted to reverse tether without interface name");
108                         return;
109                     }
110                     log("ipProvisioningThread(+" + mInterfaceName + "): " +
111                             "mNetworkInfo=" + mNetworkInfo);
112                     mIpManager = new IpManager(mContext, mInterfaceName, ipmCallback);
113                     mIpManager.startProvisioning(
114                             mIpManager.buildProvisioningConfiguration()
115                                     .withoutIpReachabilityMonitor()
116                                     .build());
117                     mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, null);
118                 }
119 
120                 linkProperties = ipmCallback.waitForProvisioning();
121                 if (linkProperties == null) {
122                     Slog.e(TAG, "IP provisioning error.");
123                     synchronized(BluetoothTetheringNetworkFactory.this) {
124                         stopIpManagerLocked();
125                         setScoreFilter(-1);
126                     }
127                     return;
128                 }
129 
130                 synchronized(BluetoothTetheringNetworkFactory.this) {
131                     mNetworkInfo.setIsAvailable(true);
132                     mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
133 
134                     // Create our NetworkAgent.
135                     mNetworkAgent = new NetworkAgent(getLooper(), mContext, NETWORK_TYPE,
136                             mNetworkInfo, mNetworkCapabilities, linkProperties, NETWORK_SCORE) {
137                         public void unwanted() {
138                             BluetoothTetheringNetworkFactory.this.onCancelRequest();
139                         };
140                     };
141                 }
142             }
143         });
144         ipProvisioningThread.start();
145     }
146 
147     // Called from NetworkFactory to indicate ConnectivityService no longer desires a Bluetooth
148     // reverse-tether network.
149     @Override
stopNetwork()150     protected void stopNetwork() {
151         // Let NetworkAgent disconnect do the teardown.
152     }
153 
154     // Called by the NetworkFactory, NetworkAgent or PanService to tear down network.
onCancelRequest()155     private synchronized void onCancelRequest() {
156         stopIpManagerLocked();
157         mInterfaceName = "";
158 
159         mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
160         if (mNetworkAgent != null) {
161             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
162             mNetworkAgent = null;
163         }
164         for (BluetoothDevice device : mPanService.getConnectedDevices()) {
165              mPanService.disconnect(device);
166         }
167     }
168 
169     // Called by PanService when a network interface for Bluetooth reverse-tethering
170     // becomes available.  We register our NetworkFactory at this point.
startReverseTether(final String iface)171     public void startReverseTether(final String iface) {
172         if (iface == null || TextUtils.isEmpty(iface)) {
173             Slog.e(TAG, "attempted to reverse tether with empty interface");
174             return;
175         }
176         synchronized(this) {
177             if (!TextUtils.isEmpty(mInterfaceName)) {
178                 Slog.e(TAG, "attempted to reverse tether while already in process");
179                 return;
180             }
181             mInterfaceName = iface;
182             // Advertise ourselves to ConnectivityService.
183             register();
184             setScoreFilter(NETWORK_SCORE);
185         }
186     }
187 
188     // Called by PanService when a network interface for Bluetooth reverse-tethering
189     // goes away.  We stop advertising ourselves to ConnectivityService at this point.
stopReverseTether()190     public synchronized void stopReverseTether() {
191         if (TextUtils.isEmpty(mInterfaceName)) {
192             Slog.e(TAG, "attempted to stop reverse tether with nothing tethered");
193             return;
194         }
195         onCancelRequest();
196         setScoreFilter(-1);
197         unregister();
198     }
199 
initNetworkCapabilities()200     private void initNetworkCapabilities() {
201         mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH);
202         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
203         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
204         // Bluetooth v3 and v4 go up to 24 Mbps.
205         // TODO: Adjust this to actual connection bandwidth.
206         mNetworkCapabilities.setLinkUpstreamBandwidthKbps(24 * 1000);
207         mNetworkCapabilities.setLinkDownstreamBandwidthKbps(24 * 1000);
208     }
209 }
210