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