OSDN Git Service

Fix PAN crash due to fd mismatch
authorNitin Shivpure <nshivpur@codeaurora.org>
Sun, 6 Sep 2015 09:34:01 +0000 (15:04 +0530)
committerScott James Remnant <keybuk@google.com>
Mon, 19 Oct 2015 17:36:23 +0000 (10:36 -0700)
A case, where tap read thread is always exist, Sometimes
data packets get recieved on older fd, which is not available.
which is causing assert due to fd mismatch in race condition.
when next pan connection is immediately available. If last pan
connection gets disconnected, then tap_read_thread should be
destroyed in btif context to fix this issue.

Bug: 24093456
Change-Id: Ic1053200a7be4c2091d6c394634831ca3fbd61df

bta/pan/bta_pan_act.c
btif/src/btif_pan.c

index 0b2a888..84b82b3 100644 (file)
@@ -601,7 +601,6 @@ void bta_pan_conn_open(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
     if(p_data->conn.result == PAN_SUCCESS)
     {
         data.status = BTA_PAN_SUCCESS;
-        bta_pan_co_open(p_scb->handle, p_scb->app_id, p_scb->local_role, p_scb->peer_role, p_scb->bd_addr);
         p_scb->pan_flow_enable = TRUE;
         p_scb->app_flow_enable = TRUE;
         bta_sys_conn_open(BTA_ID_PAN ,p_scb->app_id, p_scb->bd_addr);
@@ -648,7 +647,6 @@ void bta_pan_conn_close(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
 
     data.handle = p_data->hdr.layer_specific;
 
-
     bta_sys_conn_close( BTA_ID_PAN ,p_scb->app_id, p_scb->bd_addr);
 
     /* free all queued up data buffers */
@@ -657,8 +655,6 @@ void bta_pan_conn_close(tBTA_PAN_SCB *p_scb, tBTA_PAN_DATA *p_data)
 
     GKI_init_q(&p_scb->data_queue);
 
-    bta_pan_co_close(p_scb->handle, p_scb->app_id);
-
     bta_pan_scb_dealloc(p_scb);
 
     bta_pan_cb.p_cback(BTA_PAN_CLOSE_EVT, (tBTA_PAN *)&data);
index fc05e23..f7c0e0c 100644 (file)
@@ -276,10 +276,10 @@ static bt_status_t btpan_disconnect(const bt_bdaddr_t *bd_addr)
     btpan_conn_t* conn = btpan_find_conn_addr(bd_addr->address);
     if (conn && conn->handle >= 0)
     {
-        BTA_PanClose(conn->handle);
         /* Inform the application that the disconnect has been initiated successfully */
         btif_transfer_context(btif_in_pan_generic_evt, BTIF_PAN_CB_DISCONNECTING,
                               (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
+        BTA_PanClose(conn->handle);
         return BT_STATUS_SUCCESS;
     }
     return BT_STATUS_FAIL;
@@ -491,6 +491,62 @@ btpan_conn_t* btpan_find_conn_addr(const BD_ADDR addr)
     return NULL;
 }
 
+static void btpan_open_conn(btpan_conn_t* conn, tBTA_PAN *p_data)
+{
+    BTIF_TRACE_API("btpan_open_conn: local_role:%d, peer_role: %d,  handle:%d, conn: %p",
+            p_data->open.local_role, p_data->open.peer_role, p_data->open.handle, conn);
+
+    if (conn == NULL)
+        conn = btpan_new_conn(p_data->open.handle, p_data->open.bd_addr, p_data->open.local_role,
+                p_data->open.peer_role);
+    if (conn)
+    {
+        BTIF_TRACE_DEBUG("btpan_open_conn:tap_fd:%d, open_count:%d, "
+                "conn->handle:%d should = handle:%d, local_role:%d, remote_role:%d",
+                btpan_cb.tap_fd, btpan_cb.open_count, conn->handle, p_data->open.handle,
+                conn->local_role, conn->remote_role);
+
+        btpan_cb.open_count++;
+        conn->handle = p_data->open.handle;
+        if (btpan_cb.tap_fd < 0)
+        {
+            btpan_cb.tap_fd = btpan_tap_open();
+            if(btpan_cb.tap_fd >= 0)
+                create_tap_read_thread(btpan_cb.tap_fd);
+        }
+
+        if (btpan_cb.tap_fd >= 0)
+        {
+            btpan_cb.flow = 1;
+            conn->state = PAN_STATE_OPEN;
+        }
+    }
+}
+
+static void btpan_close_conn(btpan_conn_t* conn)
+{
+    BTIF_TRACE_API("btpan_close_conn: %p",conn);
+
+    if (conn && conn->state == PAN_STATE_OPEN)
+    {
+        BTIF_TRACE_DEBUG("btpan_close_conn: PAN_STATE_OPEN");
+
+        conn->state = PAN_STATE_CLOSE;
+        btpan_cb.open_count--;
+
+        if (btpan_cb.open_count == 0)
+        {
+            destroy_tap_read_thread();
+            if (btpan_cb.tap_fd != INVALID_FD)
+            {
+                btpan_tap_close(btpan_cb.tap_fd);
+                btpan_cb.tap_fd = INVALID_FD;
+            }
+        }
+    }
+}
+
+
 static void btpan_cleanup_conn(btpan_conn_t* conn)
 {
     if (conn)
@@ -615,6 +671,7 @@ static void bta_pan_callback_transfer(UINT16 event, char *p_param)
                 {
                     state = BTPAN_STATE_CONNECTED;
                     status = BT_STATUS_SUCCESS;
+                    btpan_open_conn(conn, p_data);
                 }
                 else
                 {
@@ -635,6 +692,7 @@ static void bta_pan_callback_transfer(UINT16 event, char *p_param)
                 btpan_conn_t* conn = btpan_find_conn_handle(p_data->close.handle);
 
                 LOG_INFO(LOG_TAG, "%s: event = BTA_PAN_CLOSE_EVT handle %d", __FUNCTION__, p_data->close.handle);
+                btpan_close_conn(conn);
 
                 if (conn && conn->handle >= 0)
                 {