1 /*
2  * Copyright (C) 2012 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.bluetooth.BluetoothPan;
21 import android.bluetooth.BluetoothProfile;
22 import android.bluetooth.IBluetoothPan;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.res.Resources.NotFoundException;
26 import android.net.ConnectivityManager;
27 import android.net.InterfaceConfiguration;
28 import android.net.LinkAddress;
29 import android.net.NetworkUtils;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.INetworkManagementService;
33 import android.os.Message;
34 import android.os.ServiceManager;
35 import android.os.UserManager;
36 import android.provider.Settings;
37 import android.util.Log;
38 
39 import com.android.bluetooth.btservice.ProfileService;
40 import com.android.bluetooth.Utils;
41 
42 import java.net.InetAddress;
43 import java.util.ArrayList;
44 import java.util.HashMap;
45 import java.util.List;
46 
47 /**
48  * Provides Bluetooth Pan Device profile, as a service in
49  * the Bluetooth application.
50  * @hide
51  */
52 public class PanService extends ProfileService {
53     private static final String TAG = "PanService";
54     private static final boolean DBG = false;
55     private static PanService sPanService;
56 
57     private static final String BLUETOOTH_IFACE_ADDR_START= "192.168.44.1";
58     private static final int BLUETOOTH_MAX_PAN_CONNECTIONS = 5;
59     private static final int BLUETOOTH_PREFIX_LENGTH        = 24;
60 
61     private HashMap<BluetoothDevice, BluetoothPanDevice> mPanDevices;
62     private ArrayList<String> mBluetoothIfaceAddresses;
63     private int mMaxPanDevices;
64     private String mPanIfName;
65     private String mNapIfaceAddr;
66     private boolean mNativeAvailable;
67 
68     private static final int MESSAGE_CONNECT = 1;
69     private static final int MESSAGE_DISCONNECT = 2;
70     private static final int MESSAGE_CONNECT_STATE_CHANGED = 11;
71     private boolean mTetherOn = false;
72 
73     private BluetoothTetheringNetworkFactory mNetworkFactory;
74 
75 
76     static {
classInitNative()77         classInitNative();
78     }
79 
getName()80     protected String getName() {
81         return TAG;
82     }
83 
initBinder()84     public IProfileServiceBinder initBinder() {
85         return new BluetoothPanBinder(this);
86     }
87 
getPanService()88     public static synchronized PanService getPanService() {
89         if (sPanService != null && sPanService.isAvailable()) {
90             if (DBG) {
91                 Log.d(TAG, "getPanService(): returning " + sPanService);
92             }
93             return sPanService;
94         }
95         if (DBG) {
96             if (sPanService == null) {
97                 Log.d(TAG, "getPanService(): service is NULL");
98             } else if (!sPanService.isAvailable()) {
99                 Log.d(TAG, "getPanService(): service is not available");
100             }
101         }
102         return null;
103     }
104 
setPanService(PanService instance)105     private static synchronized void setPanService(PanService instance) {
106         if (instance != null && instance.isAvailable()) {
107             if (DBG) {
108                 Log.d(TAG, "setPanService(): set to: " + instance);
109             }
110             sPanService = instance;
111         } else {
112             if (DBG) {
113                 if (instance == null) {
114                     Log.d(TAG, "setPanService(): service not available");
115                 } else if (!instance.isAvailable()) {
116                     Log.d(TAG, "setPanService(): service is cleaning up");
117                 }
118             }
119         }
120     }
121 
start()122     protected boolean start() {
123         mPanDevices = new HashMap<BluetoothDevice, BluetoothPanDevice>();
124         mBluetoothIfaceAddresses = new ArrayList<String>();
125         try {
126             mMaxPanDevices = getResources().getInteger(
127                                  com.android.internal.R.integer.config_max_pan_devices);
128         } catch (NotFoundException e) {
129             mMaxPanDevices = BLUETOOTH_MAX_PAN_CONNECTIONS;
130         }
131         initializeNative();
132         mNativeAvailable=true;
133 
134         mNetworkFactory = new BluetoothTetheringNetworkFactory(getBaseContext(), getMainLooper(),
135                 this);
136         setPanService(this);
137 
138         return true;
139     }
140 
stop()141     protected boolean stop() {
142         mHandler.removeCallbacksAndMessages(null);
143         return true;
144     }
145 
cleanup()146     protected boolean cleanup() {
147         if (mNativeAvailable) {
148             cleanupNative();
149             mNativeAvailable=false;
150         }
151         if(mPanDevices != null) {
152             List<BluetoothDevice> DevList = getConnectedDevices();
153             for(BluetoothDevice dev : DevList) {
154                 handlePanDeviceStateChange(dev, mPanIfName, BluetoothProfile.STATE_DISCONNECTED,
155                         BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE);
156             }
157             mPanDevices.clear();
158         }
159         return true;
160     }
161 
162     private final Handler mHandler = new Handler() {
163         @Override
164         public void handleMessage(Message msg) {
165             switch (msg.what) {
166                 case MESSAGE_CONNECT:
167                 {
168                     BluetoothDevice device = (BluetoothDevice) msg.obj;
169                     if (!connectPanNative(Utils.getByteAddress(device),
170                             BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE)) {
171                         handlePanDeviceStateChange(device, null, BluetoothProfile.STATE_CONNECTING,
172                                 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE);
173                         handlePanDeviceStateChange(device, null,
174                                 BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE,
175                                 BluetoothPan.REMOTE_NAP_ROLE);
176                         break;
177                     }
178                 }
179                     break;
180                 case MESSAGE_DISCONNECT:
181                 {
182                     BluetoothDevice device = (BluetoothDevice) msg.obj;
183                     if (!disconnectPanNative(Utils.getByteAddress(device)) ) {
184                         handlePanDeviceStateChange(device, mPanIfName,
185                                 BluetoothProfile.STATE_DISCONNECTING, BluetoothPan.LOCAL_PANU_ROLE,
186                                 BluetoothPan.REMOTE_NAP_ROLE);
187                         handlePanDeviceStateChange(device, mPanIfName,
188                                 BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE,
189                                 BluetoothPan.REMOTE_NAP_ROLE);
190                         break;
191                     }
192                 }
193                     break;
194                 case MESSAGE_CONNECT_STATE_CHANGED:
195                 {
196                     ConnectState cs = (ConnectState)msg.obj;
197                     BluetoothDevice device = getDevice(cs.addr);
198                     // TBD get iface from the msg
199                     if (DBG) {
200                         log("MESSAGE_CONNECT_STATE_CHANGED: " + device + " state: " + cs.state);
201                     }
202                     handlePanDeviceStateChange(device, mPanIfName /* iface */,
203                             convertHalState(cs.state), cs.local_role,  cs.remote_role);
204                 }
205                 break;
206             }
207         }
208     };
209 
210     /**
211      * Handlers for incoming service calls
212      */
213     private static class BluetoothPanBinder extends IBluetoothPan.Stub
214             implements IProfileServiceBinder {
215         private PanService mService;
BluetoothPanBinder(PanService svc)216         public BluetoothPanBinder(PanService svc) {
217             mService = svc;
218         }
cleanup()219         public boolean cleanup() {
220             mService = null;
221             return true;
222         }
getService()223         private PanService getService() {
224             if (!Utils.checkCaller()) {
225                 Log.w(TAG,"Pan call not allowed for non-active user");
226                 return null;
227             }
228 
229             if (mService  != null && mService.isAvailable()) {
230                 return mService;
231             }
232             return null;
233         }
connect(BluetoothDevice device)234         public boolean connect(BluetoothDevice device) {
235             PanService service = getService();
236             if (service == null) return false;
237             return service.connect(device);
238         }
disconnect(BluetoothDevice device)239         public boolean disconnect(BluetoothDevice device) {
240             PanService service = getService();
241             if (service == null) return false;
242             return service.disconnect(device);
243         }
getConnectionState(BluetoothDevice device)244         public int getConnectionState(BluetoothDevice device) {
245             PanService service = getService();
246             if (service == null) return BluetoothPan.STATE_DISCONNECTED;
247             return service.getConnectionState(device);
248         }
isPanNapOn()249         private boolean isPanNapOn() {
250             PanService service = getService();
251             if (service == null) return false;
252             return service.isPanNapOn();
253         }
isPanUOn()254         private boolean isPanUOn() {
255             if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative");
256             PanService service = getService();
257             if (service == null) return false;
258             return service.isPanUOn();
259         }
isTetheringOn()260         public boolean isTetheringOn() {
261             // TODO(BT) have a variable marking the on/off state
262             PanService service = getService();
263             if (service == null) return false;
264             return service.isTetheringOn();
265         }
setBluetoothTethering(boolean value)266         public void setBluetoothTethering(boolean value) {
267             PanService service = getService();
268             if (service == null) return;
269             Log.d(TAG, "setBluetoothTethering: " + value +", mTetherOn: " + service.mTetherOn);
270             service.setBluetoothTethering(value);
271         }
272 
getConnectedDevices()273         public List<BluetoothDevice> getConnectedDevices() {
274             PanService service = getService();
275             if (service == null) return new ArrayList<BluetoothDevice>(0);
276             return service.getConnectedDevices();
277         }
278 
getDevicesMatchingConnectionStates(int[] states)279         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
280             PanService service = getService();
281             if (service == null) return new ArrayList<BluetoothDevice>(0);
282             return service.getDevicesMatchingConnectionStates(states);
283         }
284     };
285 
connect(BluetoothDevice device)286     public boolean connect(BluetoothDevice device) {
287         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
288         if (getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) {
289             Log.e(TAG, "Pan Device not disconnected: " + device);
290             return false;
291         }
292         Message msg = mHandler.obtainMessage(MESSAGE_CONNECT,device);
293         mHandler.sendMessage(msg);
294         return true;
295     }
296 
disconnect(BluetoothDevice device)297     public boolean disconnect(BluetoothDevice device) {
298         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
299         Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT,device);
300         mHandler.sendMessage(msg);
301         return true;
302     }
303 
getConnectionState(BluetoothDevice device)304     public int getConnectionState(BluetoothDevice device) {
305         BluetoothPanDevice panDevice = mPanDevices.get(device);
306         if (panDevice == null) {
307             return BluetoothPan.STATE_DISCONNECTED;
308         }
309         return panDevice.mState;
310     }
311 
isPanNapOn()312     boolean isPanNapOn() {
313         if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative");
314         return (getPanLocalRoleNative() & BluetoothPan.LOCAL_NAP_ROLE) != 0;
315     }
isPanUOn()316     boolean isPanUOn() {
317         if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative");
318         return (getPanLocalRoleNative() & BluetoothPan.LOCAL_PANU_ROLE) != 0;
319     }
isTetheringOn()320     public boolean isTetheringOn() {
321         // TODO(BT) have a variable marking the on/off state
322         return mTetherOn;
323     }
324 
setBluetoothTethering(boolean value)325     void setBluetoothTethering(boolean value) {
326         if(DBG) Log.d(TAG, "setBluetoothTethering: " + value +", mTetherOn: " + mTetherOn);
327         ConnectivityManager.enforceTetherChangePermission(getBaseContext());
328         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
329         UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
330         if (um.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
331             throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
332         }
333         if(mTetherOn != value) {
334             //drop any existing panu or pan-nap connection when changing the tethering state
335             mTetherOn = value;
336             List<BluetoothDevice> DevList = getConnectedDevices();
337             for(BluetoothDevice dev : DevList)
338                 disconnect(dev);
339         }
340     }
341 
setPriority(BluetoothDevice device, int priority)342     public boolean setPriority(BluetoothDevice device, int priority) {
343         if (device == null) {
344             throw new IllegalArgumentException("Null device");
345         }
346         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
347         Settings.Global.putInt(getContentResolver(),
348                 Settings.Global.getBluetoothPanPriorityKey(device.getAddress()),
349                 priority);
350         if (DBG) {
351             Log.d(TAG,"Saved priority " + device + " = " + priority);
352         }
353         return true;
354     }
355 
getPriority(BluetoothDevice device)356     public int getPriority(BluetoothDevice device) {
357         if (device == null) throw new IllegalArgumentException("Null device");
358         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
359         return Settings.Global.getInt(getContentResolver(),
360                 Settings.Global.getBluetoothPanPriorityKey(device.getAddress()),
361                 BluetoothProfile.PRIORITY_UNDEFINED);
362     }
363 
getConnectedDevices()364     public List<BluetoothDevice> getConnectedDevices() {
365         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
366         List<BluetoothDevice> devices = getDevicesMatchingConnectionStates(
367                 new int[] {BluetoothProfile.STATE_CONNECTED});
368         return devices;
369     }
370 
getDevicesMatchingConnectionStates(int[] states)371     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
372          enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
373         List<BluetoothDevice> panDevices = new ArrayList<BluetoothDevice>();
374 
375         for (BluetoothDevice device: mPanDevices.keySet()) {
376             int panDeviceState = getConnectionState(device);
377             for (int state : states) {
378                 if (state == panDeviceState) {
379                     panDevices.add(device);
380                     break;
381                 }
382             }
383         }
384         return panDevices;
385     }
386 
387     static protected class ConnectState {
ConnectState(byte[] address, int state, int error, int local_role, int remote_role)388         public ConnectState(byte[] address, int state, int error, int local_role, int remote_role) {
389             this.addr = address;
390             this.state = state;
391             this.error = error;
392             this.local_role = local_role;
393             this.remote_role = remote_role;
394         }
395         byte[] addr;
396         int state;
397         int error;
398         int local_role;
399         int remote_role;
400     };
onConnectStateChanged(byte[] address, int state, int error, int local_role, int remote_role)401     private void onConnectStateChanged(byte[] address, int state, int error, int local_role,
402             int remote_role) {
403         if (DBG) {
404             log("onConnectStateChanged: " + state + ", local role:" + local_role +
405                     ", remote_role: " + remote_role);
406         }
407         Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED);
408         msg.obj = new ConnectState(address, state, error, local_role, remote_role);
409         mHandler.sendMessage(msg);
410     }
onControlStateChanged(int local_role, int state, int error, String ifname)411     private void onControlStateChanged(int local_role, int state, int error, String ifname) {
412         if (DBG)
413             log("onControlStateChanged: " + state + ", error: " + error + ", ifname: " + ifname);
414         if(error == 0)
415             mPanIfName = ifname;
416     }
417 
convertHalState(int halState)418     private static int convertHalState(int halState) {
419         switch (halState) {
420             case CONN_STATE_CONNECTED:
421                 return BluetoothProfile.STATE_CONNECTED;
422             case CONN_STATE_CONNECTING:
423                 return BluetoothProfile.STATE_CONNECTING;
424             case CONN_STATE_DISCONNECTED:
425                 return BluetoothProfile.STATE_DISCONNECTED;
426             case CONN_STATE_DISCONNECTING:
427                 return BluetoothProfile.STATE_DISCONNECTING;
428             default:
429                 Log.e(TAG, "bad pan connection state: " + halState);
430                 return BluetoothProfile.STATE_DISCONNECTED;
431         }
432     }
433 
handlePanDeviceStateChange(BluetoothDevice device, String iface, int state, int local_role, int remote_role)434     void handlePanDeviceStateChange(BluetoothDevice device,
435                                     String iface, int state, int local_role, int remote_role) {
436         if(DBG) {
437             Log.d(TAG, "handlePanDeviceStateChange: device: " + device + ", iface: " + iface +
438                     ", state: " + state + ", local_role:" + local_role + ", remote_role:" +
439                     remote_role);
440         }
441         int prevState;
442 
443         BluetoothPanDevice panDevice = mPanDevices.get(device);
444         if (panDevice == null) {
445             Log.i(TAG, "state " + state + " Num of connected pan devices: " + mPanDevices.size());
446             prevState = BluetoothProfile.STATE_DISCONNECTED;
447             panDevice = new BluetoothPanDevice(state, iface, local_role);
448             mPanDevices.put(device, panDevice);
449         } else {
450             prevState = panDevice.mState;
451             panDevice.mState = state;
452             panDevice.mLocalRole = local_role;
453             panDevice.mIface = iface;
454         }
455 
456         // Avoid race condition that gets this class stuck in STATE_DISCONNECTING. While we
457         // are in STATE_CONNECTING, if a BluetoothPan#disconnect call comes in, the original
458         // connect call will put us in STATE_DISCONNECTED. Then, the disconnect completes and
459         // changes the state to STATE_DISCONNECTING. All future calls to BluetoothPan#connect
460         // will fail until the caller explicitly calls BluetoothPan#disconnect.
461         if (prevState == BluetoothProfile.STATE_DISCONNECTED && state == BluetoothProfile.STATE_DISCONNECTING) {
462             Log.d(TAG, "Ignoring state change from " + prevState + " to " + state);
463             return;
464         }
465 
466         Log.d(TAG, "handlePanDeviceStateChange preState: " + prevState + " state: " + state);
467         if (prevState == state) return;
468         if (remote_role == BluetoothPan.LOCAL_PANU_ROLE) {
469             if (state == BluetoothProfile.STATE_CONNECTED) {
470                 if ((!mTetherOn) || (local_role == BluetoothPan.LOCAL_PANU_ROLE)) {
471                     Log.d(TAG, "handlePanDeviceStateChange BT tethering is off/Local role"
472                             + " is PANU drop the connection");
473                     mPanDevices.remove(device);
474                     disconnectPanNative(Utils.getByteAddress(device));
475                     return;
476                 }
477                 Log.d(TAG, "handlePanDeviceStateChange LOCAL_NAP_ROLE:REMOTE_PANU_ROLE");
478                 if (mNapIfaceAddr == null) {
479                     mNapIfaceAddr = startTethering(iface);
480                     if (mNapIfaceAddr == null) {
481                         Log.e(TAG, "Error seting up tether interface");
482                         mPanDevices.remove(device);
483                         disconnectPanNative(Utils.getByteAddress(device));
484                         return;
485                     }
486                 }
487             } else if (state == BluetoothProfile.STATE_DISCONNECTED) {
488                 mPanDevices.remove(device);
489                 Log.i(TAG, "remote(PANU) is disconnected, Remaining connected PANU devices: "
490                         + mPanDevices.size());
491                 if (mNapIfaceAddr != null && mPanDevices.size() == 0) {
492                     stopTethering(iface);
493                     mNapIfaceAddr = null;
494                 }
495             }
496         } else if (mNetworkFactory != null) {
497             // PANU Role = reverse Tether
498             Log.d(TAG, "handlePanDeviceStateChange LOCAL_PANU_ROLE:REMOTE_NAP_ROLE state = " +
499                     state + ", prevState = " + prevState);
500             if (state == BluetoothProfile.STATE_CONNECTED) {
501                 mNetworkFactory.startReverseTether(iface);
502            } else if (state == BluetoothProfile.STATE_DISCONNECTED &&
503                    (prevState == BluetoothProfile.STATE_CONNECTED ||
504                    prevState == BluetoothProfile.STATE_DISCONNECTING)) {
505                 mNetworkFactory.stopReverseTether();
506                 mPanDevices.remove(device);
507             }
508         }
509 
510         /* Notifying the connection state change of the profile before sending the intent for
511            connection state change, as it was causing a race condition, with the UI not being
512            updated with the correct connection state. */
513         Log.d(TAG, "Pan Device state : device: " + device + " State:" +
514                        prevState + "->" + state);
515         Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
516         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
517         intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState);
518         intent.putExtra(BluetoothPan.EXTRA_STATE, state);
519         intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, local_role);
520         sendBroadcast(intent, BLUETOOTH_PERM);
521     }
522 
startTethering(String iface)523     private String startTethering(String iface) {
524         return configureBtIface(true, iface);
525     }
526 
stopTethering(String iface)527     private String stopTethering(String iface) {
528         return configureBtIface(false, iface);
529     }
530 
configureBtIface(boolean enable, String iface)531     private String configureBtIface(boolean enable, String iface) {
532         Log.i(TAG, "configureBtIface: " + iface + " enable: " + enable);
533 
534         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
535         INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
536         ConnectivityManager cm =
537             (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
538         String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
539 
540         // bring toggle the interfaces
541         String[] currentIfaces = new String[0];
542         try {
543             currentIfaces = service.listInterfaces();
544         } catch (Exception e) {
545             Log.e(TAG, "Error listing Interfaces :" + e);
546             return null;
547         }
548 
549         boolean found = false;
550         for (String currIface: currentIfaces) {
551             if (currIface.equals(iface)) {
552                 found = true;
553                 break;
554             }
555         }
556 
557         if (!found) return null;
558 
559         InterfaceConfiguration ifcg = null;
560         String address = null;
561         try {
562             ifcg = service.getInterfaceConfig(iface);
563             if (ifcg != null) {
564                 InetAddress addr = null;
565                 LinkAddress linkAddr = ifcg.getLinkAddress();
566                 if (linkAddr == null || (addr = linkAddr.getAddress()) == null ||
567                         addr.equals(NetworkUtils.numericToInetAddress("0.0.0.0")) ||
568                         addr.equals(NetworkUtils.numericToInetAddress("::0"))) {
569                     address = BLUETOOTH_IFACE_ADDR_START;
570                     addr = NetworkUtils.numericToInetAddress(address);
571                 }
572 
573                 ifcg.setLinkAddress(new LinkAddress(addr, BLUETOOTH_PREFIX_LENGTH));
574                 if (enable) {
575                     ifcg.setInterfaceUp();
576                 } else {
577                     ifcg.setInterfaceDown();
578                 }
579 
580                 ifcg.clearFlag("running");
581                 service.setInterfaceConfig(iface, ifcg);
582 
583                 if (enable) {
584                     int tetherStatus = cm.tether(iface);
585                     if (tetherStatus != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
586                         Log.e(TAG, "Error tethering "+ iface + " tetherStatus: " + tetherStatus);
587                         return null;
588                     }
589                 } else {
590                     int untetherStatus = cm.untether(iface);
591                     Log.i(TAG, "Untethered: "+ iface + " untetherStatus: " + untetherStatus);
592                 }
593             }
594         } catch (Exception e) {
595             Log.e(TAG, "Error configuring interface " + iface + ", :" + e);
596             return null;
597         }
598         return address;
599     }
600 
getConnectedPanDevices()601     private List<BluetoothDevice> getConnectedPanDevices() {
602         List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
603 
604         for (BluetoothDevice device: mPanDevices.keySet()) {
605             if (getPanDeviceConnectionState(device) == BluetoothProfile.STATE_CONNECTED) {
606                 devices.add(device);
607             }
608         }
609         return devices;
610     }
611 
getPanDeviceConnectionState(BluetoothDevice device)612     private int getPanDeviceConnectionState(BluetoothDevice device) {
613         BluetoothPanDevice panDevice = mPanDevices.get(device);
614         if (panDevice == null) {
615             return BluetoothProfile.STATE_DISCONNECTED;
616         }
617         return panDevice.mState;
618     }
619 
620     @Override
dump(StringBuilder sb)621     public void dump(StringBuilder sb) {
622         super.dump(sb);
623         println(sb, "mMaxPanDevices: " + mMaxPanDevices);
624         println(sb, "mPanIfName: " + mPanIfName);
625         println(sb, "mTetherOn: " + mTetherOn);
626         println(sb, "mPanDevices:");
627         for (BluetoothDevice device : mPanDevices.keySet()) {
628             println(sb, "  " + device + " : " + mPanDevices.get(device));
629         }
630     }
631 
632     private class BluetoothPanDevice {
633         private int mState;
634         private String mIface;
635         private int mLocalRole; // Which local role is this PAN device bound to
636 
BluetoothPanDevice(int state, String iface, int localRole)637         BluetoothPanDevice(int state, String iface, int localRole) {
638             mState = state;
639             mIface = iface;
640             mLocalRole = localRole;
641         }
642     }
643 
644     // Constants matching Hal header file bt_hh.h
645     // bthh_connection_state_t
646     private final static int CONN_STATE_CONNECTED = 0;
647     private final static int CONN_STATE_CONNECTING = 1;
648     private final static int CONN_STATE_DISCONNECTED = 2;
649     private final static int CONN_STATE_DISCONNECTING = 3;
650 
classInitNative()651     private native static void classInitNative();
initializeNative()652     private native void initializeNative();
cleanupNative()653     private native void cleanupNative();
connectPanNative(byte[] btAddress, int local_role, int remote_role)654     private native boolean connectPanNative(byte[] btAddress, int local_role, int remote_role);
disconnectPanNative(byte[] btAddress)655     private native boolean disconnectPanNative(byte[] btAddress);
enablePanNative(int local_role)656     private native boolean enablePanNative(int local_role);
getPanLocalRoleNative()657     private native int getPanLocalRoleNative();
658 
659 }
660