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