Fix PAN and AV role switch war

Bug: 23740164
Change-Id: Ib26a64b624c711443201adc4fde6b041ecb0dde1
diff --git a/bta/dm/bta_dm_act.c b/bta/dm/bta_dm_act.c
index eb49637..5230d8f 100644
--- a/bta/dm/bta_dm_act.c
+++ b/bta/dm/bta_dm_act.c
@@ -3689,7 +3689,8 @@
                   versions are stored in a blacklist and role switch with these devices are
                   delayed to avoid the collision with link encryption setup */
 
-                    if (delay_role_switch == FALSE)
+                    if (bta_dm_cb.device_list.peer_device[i].pref_role != BTA_SLAVE_ROLE_ONLY &&
+                            delay_role_switch == FALSE)
                     {
                         BTM_SwitchRole (bta_dm_cb.device_list.peer_device[i].peer_bdaddr,
                                         HCI_ROLE_MASTER, NULL);
diff --git a/bta/dm/bta_dm_cfg.c b/bta/dm/bta_dm_cfg.c
index 014c431..744a6fc 100644
--- a/bta/dm/bta_dm_cfg.c
+++ b/bta/dm/bta_dm_cfg.c
@@ -86,7 +86,11 @@
 #define BTA_AV_ROLE BTA_MASTER_ROLE_PREF
 #endif
 
-#define BTA_DM_NUM_RM_ENTRY    4
+#ifndef BTA_PANU_ROLE
+/* By default, AV role (backward BTA_MASTER_ROLE_PREF) */
+#define BTA_PANU_ROLE BTA_SLAVE_ROLE_ONLY
+#endif
+#define BTA_DM_NUM_RM_ENTRY    6
 
 /* appids for PAN used by insight sample application
    these have to be same as defined in btui_int.h */
@@ -100,8 +104,10 @@
 const tBTA_DM_RM bta_dm_rm_cfg[] =
 {
     {BTA_ID_SYS, BTA_DM_NUM_RM_ENTRY, BTA_DM_SCATTERNET},
-    {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_MASTER_ROLE_ONLY},
-    {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_MASTER_ROLE_ONLY},
+    {BTA_ID_PAN, BTUI_PAN_ID_NAP, BTA_ANY_ROLE},
+    {BTA_ID_PAN, BTUI_PAN_ID_GN, BTA_ANY_ROLE},
+    {BTA_ID_PAN, BTA_APP_ID_PAN_MULTI, BTA_MASTER_ROLE_ONLY},
+    {BTA_ID_PAN, BTUI_PAN_ID_PANU, BTA_PANU_ROLE},
     {BTA_ID_HH,  BTA_ALL_APP_ID, BTA_HH_ROLE},
     {BTA_ID_AV,  BTA_ALL_APP_ID, BTA_AV_ROLE}
 };
diff --git a/bta/include/bta_api.h b/bta/include/bta_api.h
index a470d1a..648d118 100644
--- a/bta/include/bta_api.h
+++ b/bta/include/bta_api.h
@@ -181,6 +181,7 @@
 /* Ignore for Discoverable, Connectable only for LE modes */
 #define BTA_DM_LE_IGNORE           0xFF00
 
+#define BTA_APP_ID_PAN_MULTI    0xFE    /* app id for pan multiple connection */
 #define BTA_ALL_APP_ID          0xFF
 
 /* Discoverable Modes */
@@ -248,6 +249,7 @@
 #define BTA_ANY_ROLE          0x00
 #define BTA_MASTER_ROLE_PREF  0x01
 #define BTA_MASTER_ROLE_ONLY  0x02
+#define BTA_SLAVE_ROLE_ONLY   0x03     /* Used for PANU only, skip role switch to master */
 
 typedef UINT8 tBTA_PREF_ROLES;
 
diff --git a/bta/pan/bta_pan_act.c b/bta/pan/bta_pan_act.c
index ef7bee7..d4bd1c1 100644
--- a/bta/pan/bta_pan_act.c
+++ b/bta/pan/bta_pan_act.c
@@ -295,6 +295,53 @@
 
 /*******************************************************************************
 **
+** Function         bta_pan_has_multiple_connections
+**
+** Description      Check whether there are multiple GN/NAP connections to
+**                  different devices
+**
+**
+** Returns          BOOLEAN
+**
+*******************************************************************************/
+static BOOLEAN bta_pan_has_multiple_connections(UINT8 app_id)
+{
+    tBTA_PAN_SCB *p_scb = NULL;
+    BOOLEAN     found = FALSE;
+    BD_ADDR     bd_addr;
+
+    for (UINT8 index = 0; index < BTA_PAN_NUM_CONN; index++)
+    {
+        p_scb = &bta_pan_cb.scb[index];
+        if (p_scb->in_use == TRUE && app_id == p_scb->app_id)
+        {
+            /* save temp bd_addr */
+            bdcpy(bd_addr, p_scb->bd_addr);
+            found = TRUE;
+            break;
+        }
+    }
+
+    /* If cannot find a match then there is no connection at all */
+    if (found == FALSE)
+        return FALSE;
+
+    /* Find whether there is another connection with different device other than PANU.
+        Could be same service or different service */
+    for (UINT8 index = 0; index < BTA_PAN_NUM_CONN; index++)
+    {
+        p_scb = &bta_pan_cb.scb[index];
+        if (p_scb->in_use == TRUE && p_scb->app_id != bta_pan_cb.app_id[0] &&
+                bdcmp(bd_addr, p_scb->bd_addr))
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/*******************************************************************************
+**
 ** Function         bta_pan_enable
 **
 ** Description
@@ -565,6 +612,18 @@
         data.status = BTA_PAN_FAIL;
     }
 
+    p_scb->pan_flow_enable = TRUE;
+    p_scb->app_flow_enable = TRUE;
+
+    /* If app_id is NAP/GN, check whether there are multiple connections.
+       If there are, provide a special app_id to dm to enforce master role only. */
+    if ((p_scb->app_id == bta_pan_cb.app_id[1] || p_scb->app_id == bta_pan_cb.app_id[2]) &&
+            bta_pan_has_multiple_connections(p_scb->app_id))
+    {
+        p_scb->app_id = BTA_APP_ID_PAN_MULTI;
+    }
+
+    bta_sys_conn_open(BTA_ID_PAN, p_scb->app_id, p_scb->bd_addr);
     bta_pan_cb.p_cback(BTA_PAN_OPEN_EVT, (tBTA_PAN *)&data);