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.NetworkStateTracker;
31 import android.net.NetworkUtils;
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 LinkProperties mLinkProperties;
61     private NetworkAgent mNetworkAgent;
62 
BluetoothTetheringNetworkFactory(Context context, Looper looper, PanService panService)63     public BluetoothTetheringNetworkFactory(Context context, Looper looper, PanService panService) {
64         super(looper, context, NETWORK_TYPE, new NetworkCapabilities());
65 
66         mContext = context;
67         mPanService = panService;
68 
69         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_BLUETOOTH, 0, NETWORK_TYPE, "");
70         mLinkProperties = new LinkProperties();
71         mNetworkCapabilities = new NetworkCapabilities();
72         initNetworkCapabilities();
73         setCapabilityFilter(mNetworkCapabilities);
74     }
75 
76     // Called by NetworkFactory when PanService and NetworkFactory both desire a Bluetooth
77     // reverse-tether connection.  A network interface for Bluetooth reverse-tethering can be
78     // assumed to be available because we only register our NetworkFactory when it is so.
79     @Override
startNetwork()80     protected void startNetwork() {
81         // TODO: Handle DHCP renew.
82         Thread dhcpThread = new Thread(new Runnable() {
83             public void run() {
84                 LinkProperties linkProperties;
85                 synchronized (BluetoothTetheringNetworkFactory.this) {
86                     linkProperties = mLinkProperties;
87                     if (linkProperties.getInterfaceName() == null) {
88                         Slog.e(TAG, "attempted to reverse tether without interface name");
89                         return;
90                     }
91                     log("dhcpThread(+" + linkProperties.getInterfaceName() +
92                             "): mNetworkInfo=" + mNetworkInfo);
93                 }
94 
95                 DhcpResults dhcpResults = new DhcpResults();
96                 // TODO: Handle DHCP renewals better.
97                 // In general runDhcp handles DHCP renewals for us, because
98                 // the dhcp client stays running, but if the renewal fails,
99                 // we will lose our IP address and connectivity without
100                 // noticing.
101                 if (!NetworkUtils.runDhcp(linkProperties.getInterfaceName(), dhcpResults)) {
102                     Slog.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
103                     synchronized(BluetoothTetheringNetworkFactory.this) {
104                         setScoreFilter(-1);
105                     }
106                     return;
107                 }
108 
109                 synchronized(BluetoothTetheringNetworkFactory.this) {
110                     mLinkProperties = dhcpResults.toLinkProperties(
111                             linkProperties.getInterfaceName());
112                     mNetworkInfo.setIsAvailable(true);
113                     mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
114 
115                     // Create our NetworkAgent.
116                     mNetworkAgent = new NetworkAgent(getLooper(), mContext, NETWORK_TYPE,
117                             mNetworkInfo, mNetworkCapabilities, mLinkProperties, NETWORK_SCORE) {
118                         public void unwanted() {
119                             BluetoothTetheringNetworkFactory.this.onCancelRequest();
120                         };
121                     };
122                 }
123             }
124         });
125         dhcpThread.start();
126     }
127 
128     // Called from NetworkFactory to indicate ConnectivityService no longer desires a Bluetooth
129     // reverse-tether network.
130     @Override
stopNetwork()131     protected void stopNetwork() {
132         // Let NetworkAgent disconnect do the teardown.
133     }
134 
135     // Called by the NetworkFactory, NetworkAgent or PanService to tear down network.
onCancelRequest()136     private synchronized void onCancelRequest() {
137         if (!TextUtils.isEmpty(mLinkProperties.getInterfaceName())) {
138             NetworkUtils.stopDhcp(mLinkProperties.getInterfaceName());
139         }
140         mLinkProperties.clear();
141         mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
142         if (mNetworkAgent != null) {
143             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
144             mNetworkAgent = null;
145         }
146         for (BluetoothDevice device : mPanService.getConnectedDevices()) {
147              mPanService.disconnect(device);
148         }
149     }
150 
151     // Called by PanService when a network interface for Bluetooth reverse-tethering
152     // becomes available.  We register our NetworkFactory at this point.
startReverseTether(final String iface)153     public void startReverseTether(final String iface) {
154         if (iface == null || TextUtils.isEmpty(iface)) {
155             Slog.e(TAG, "attempted to reverse tether with empty interface");
156             return;
157         }
158         synchronized(this) {
159             if (mLinkProperties.getInterfaceName() != null) {
160                 Slog.e(TAG, "attempted to reverse tether while already in process");
161                 return;
162             }
163             mLinkProperties = new LinkProperties();
164             mLinkProperties.setInterfaceName(iface);
165             // Advertise ourselves to ConnectivityService.
166             register();
167             setScoreFilter(NETWORK_SCORE);
168         }
169     }
170 
171     // Called by PanService when a network interface for Bluetooth reverse-tethering
172     // goes away.  We stop advertising ourselves to ConnectivityService at this point.
stopReverseTether()173     public synchronized void stopReverseTether() {
174         if (TextUtils.isEmpty(mLinkProperties.getInterfaceName())) {
175             Slog.e(TAG, "attempted to stop reverse tether with nothing tethered");
176             return;
177         }
178         onCancelRequest();
179         setScoreFilter(-1);
180         unregister();
181     }
182 
initNetworkCapabilities()183     private void initNetworkCapabilities() {
184         mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH);
185         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
186         mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
187         // Bluetooth v3 and v4 go up to 24 Mbps.
188         // TODO: Adjust this to actual connection bandwidth.
189         mNetworkCapabilities.setLinkUpstreamBandwidthKbps(24 * 1000);
190         mNetworkCapabilities.setLinkDownstreamBandwidthKbps(24 * 1000);
191     }
192 }
193