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