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