OSDN Git Service

PAN: Avoid reconfiguration of bt-pan interface in NAP role
authorNitin Shivpure <nshivpur@codeaurora.org>
Thu, 16 Jun 2016 15:15:29 +0000 (20:45 +0530)
committerAjay Panicker <apanicke@google.com>
Thu, 14 Jul 2016 19:06:45 +0000 (19:06 +0000)
Issue:
Browsing is not working with multiple remote PANU Device(s).

Root Cause:
When the 1st remote PANU is connected, the bt-pan interface gets
configured. As soon as 2nd PANU is connected, the bt-pan interface
goes into a bad state. The second device is able to write Ethernet
packets on the bt-pan interface (TUN driver) after reconfiguration,
but it is unable to read Ethernet packets from the interface.

Fix:
If the bt-pan interface is already configured in the NAP role,
then do not reconfigure bt-pan when the 2nd PANU is connected.

Bug: 29992925
Change-Id: Ib6e0cb91d573649af45ffe25c7095a4bd74a5022

src/com/android/bluetooth/pan/PanService.java

index ea9b97e..6456b7d 100755 (executable)
@@ -67,6 +67,7 @@ public class PanService extends ProfileService {
     private ArrayList<String> mBluetoothIfaceAddresses;
     private int mMaxPanDevices;
     private String mPanIfName;
+    private String mNapIfaceAddr;
     private boolean mNativeAvailable;
 
     private static final int MESSAGE_CONNECT = 1;
@@ -125,9 +126,6 @@ public class PanService extends ProfileService {
             }
             mPanDevices.clear();
         }
-        if(mBluetoothIfaceAddresses != null) {
-            mBluetoothIfaceAddresses.clear();
-        }
         return true;
     }
 
@@ -389,13 +387,18 @@ public class PanService extends ProfileService {
                     remote_role);
         }
         int prevState;
-        String ifaceAddr = null;
+
         BluetoothPanDevice panDevice = mPanDevices.get(device);
         if (panDevice == null) {
+            Log.i(TAG, "state " + state + " Num of connected pan devices: " + mPanDevices.size());
             prevState = BluetoothProfile.STATE_DISCONNECTED;
+            panDevice = new BluetoothPanDevice(state, iface, local_role);
+            mPanDevices.put(device, panDevice);
         } else {
             prevState = panDevice.mState;
-            ifaceAddr = panDevice.mIfaceAddr;
+            panDevice.mState = state;
+            panDevice.mLocalRole = local_role;
+            panDevice.mIface = iface;
         }
 
         // Avoid race condition that gets this class stuck in STATE_DISCONNECTING. While we
@@ -412,20 +415,30 @@ public class PanService extends ProfileService {
         if (prevState == state) return;
         if (remote_role == BluetoothPan.LOCAL_PANU_ROLE) {
             if (state == BluetoothProfile.STATE_CONNECTED) {
-                if((!mTetherOn)||(local_role == BluetoothPan.LOCAL_PANU_ROLE)){
-                    Log.d(TAG,"handlePanDeviceStateChange BT tethering is off/Local role is PANU "+
-                              "drop the connection");
+                if ((!mTetherOn) || (local_role == BluetoothPan.LOCAL_PANU_ROLE)) {
+                    Log.d(TAG, "handlePanDeviceStateChange BT tethering is off/Local role"
+                            + " is PANU drop the connection");
+                    mPanDevices.remove(device);
                     disconnectPanNative(Utils.getByteAddress(device));
                     return;
                 }
                 Log.d(TAG, "handlePanDeviceStateChange LOCAL_NAP_ROLE:REMOTE_PANU_ROLE");
-                ifaceAddr = enableTethering(iface);
-                if (ifaceAddr == null) Log.e(TAG, "Error seting up tether interface");
-
+                if (mNapIfaceAddr == null) {
+                    mNapIfaceAddr = startTethering(iface);
+                    if (mNapIfaceAddr == null) {
+                        Log.e(TAG, "Error seting up tether interface");
+                        mPanDevices.remove(device);
+                        disconnectPanNative(Utils.getByteAddress(device));
+                        return;
+                    }
+                }
             } else if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                if (ifaceAddr != null) {
-                    mBluetoothIfaceAddresses.remove(ifaceAddr);
-                    ifaceAddr = null;
+                mPanDevices.remove(device);
+                Log.i(TAG, "remote(PANU) is disconnected, Remaining connected PANU devices: "
+                        + mPanDevices.size());
+                if (mNapIfaceAddr != null && mPanDevices.size() == 0) {
+                    stopTethering(iface);
+                    mNapIfaceAddr = null;
                 }
             }
         } else if (mNetworkFactory != null) {
@@ -438,19 +451,10 @@ public class PanService extends ProfileService {
                    (prevState == BluetoothProfile.STATE_CONNECTED ||
                    prevState == BluetoothProfile.STATE_DISCONNECTING)) {
                 mNetworkFactory.stopReverseTether();
+                mPanDevices.remove(device);
             }
         }
 
-        if (panDevice == null) {
-            panDevice = new BluetoothPanDevice(state, ifaceAddr, iface, local_role);
-            mPanDevices.put(device, panDevice);
-        } else {
-            panDevice.mState = state;
-            panDevice.mIfaceAddr = ifaceAddr;
-            panDevice.mLocalRole = local_role;
-            panDevice.mIface = iface;
-        }
-
         /* Notifying the connection state change of the profile before sending the intent for
            connection state change, as it was causing a race condition, with the UI not being
            updated with the correct connection state. */
@@ -465,9 +469,16 @@ public class PanService extends ProfileService {
         sendBroadcast(intent, BLUETOOTH_PERM);
     }
 
-    // configured when we start tethering
-    private String enableTethering(String iface) {
-        if (DBG) Log.d(TAG, "updateTetherState:" + iface);
+    private String startTethering(String iface) {
+        return configureBtIface(true, iface);
+    }
+
+    private String stopTethering(String iface) {
+        return configureBtIface(false, iface);
+    }
+
+    private String configureBtIface(boolean enable, String iface) {
+        Log.i(TAG, "configureBtIface: " + iface + " enable: " + enable);
 
         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
         INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
@@ -494,10 +505,8 @@ public class PanService extends ProfileService {
 
         if (!found) return null;
 
-        String address = createNewTetheringAddressLocked();
-        if (address == null) return null;
-
         InterfaceConfiguration ifcg = null;
+        String address = null;
         try {
             ifcg = service.getInterfaceConfig(iface);
             if (ifcg != null) {
@@ -506,15 +515,29 @@ public class PanService extends ProfileService {
                 if (linkAddr == null || (addr = linkAddr.getAddress()) == null ||
                         addr.equals(NetworkUtils.numericToInetAddress("0.0.0.0")) ||
                         addr.equals(NetworkUtils.numericToInetAddress("::0"))) {
+                    address = BLUETOOTH_IFACE_ADDR_START;
                     addr = NetworkUtils.numericToInetAddress(address);
                 }
-                ifcg.setInterfaceUp();
+
                 ifcg.setLinkAddress(new LinkAddress(addr, BLUETOOTH_PREFIX_LENGTH));
+                if (enable) {
+                    ifcg.setInterfaceUp();
+                } else {
+                    ifcg.setInterfaceDown();
+                }
+
                 ifcg.clearFlag("running");
-                // TODO(BT) ifcg.interfaceFlags = ifcg.interfaceFlags.replace("  "," ");
                 service.setInterfaceConfig(iface, ifcg);
-                if (cm.tether(iface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
-                    Log.e(TAG, "Error tethering "+iface);
+
+                if (enable) {
+                    int tetherStatus = cm.tether(iface);
+                    if (tetherStatus != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                        Log.e(TAG, "Error tethering "+ iface + " tetherStatus: " + tetherStatus);
+                        return null;
+                    }
+                } else {
+                    int untetherStatus = cm.untether(iface);
+                    Log.i(TAG, "Untethered: "+ iface + " untetherStatus: " + untetherStatus);
                 }
             }
         } catch (Exception e) {
@@ -524,25 +547,6 @@ public class PanService extends ProfileService {
         return address;
     }
 
-    private String createNewTetheringAddressLocked() {
-        if (getConnectedPanDevices().size() == mMaxPanDevices) {
-            if (DBG) Log.d(TAG, "Max PAN device connections reached");
-            return null;
-        }
-        String address = BLUETOOTH_IFACE_ADDR_START;
-        while (true) {
-            if (mBluetoothIfaceAddresses.contains(address)) {
-                String[] addr = address.split("\\.");
-                Integer newIp = Integer.parseInt(addr[2]) + 1;
-                address = address.replace(addr[2], newIp.toString());
-            } else {
-                break;
-            }
-        }
-        mBluetoothIfaceAddresses.add(address);
-        return address;
-    }
-
     private List<BluetoothDevice> getConnectedPanDevices() {
         List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
 
@@ -572,21 +576,15 @@ public class PanService extends ProfileService {
         for (BluetoothDevice device : mPanDevices.keySet()) {
             println(sb, "  " + device + " : " + mPanDevices.get(device));
         }
-        println(sb, "mBluetoothIfaceAddresses:");
-        for (String address : mBluetoothIfaceAddresses) {
-            println(sb, "  " + address);
-        }
     }
 
     private class BluetoothPanDevice {
         private int mState;
-        private String mIfaceAddr;
         private String mIface;
         private int mLocalRole; // Which local role is this PAN device bound to
 
-        BluetoothPanDevice(int state, String ifaceAddr, String iface, int localRole) {
+        BluetoothPanDevice(int state, String iface, int localRole) {
             mState = state;
-            mIfaceAddr = ifaceAddr;
             mIface = iface;
             mLocalRole = localRole;
         }