Merge "Don't send a dummy 0 HID event when connection is closed" into klp-modular-dev
diff --git a/stack/gatt/att_protocol.c b/stack/gatt/att_protocol.c
index 9c715af..3348599 100644
--- a/stack/gatt/att_protocol.c
+++ b/stack/gatt/att_protocol.c
@@ -495,7 +495,7 @@
                 /* do not enq cmd if handle value confirmation or set request */
                 if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
                 {
-                    gatt_start_rsp_timer (p_tcb);
+                    gatt_start_rsp_timer (clcb_idx);
                     gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
                 }
             }
diff --git a/stack/gatt/gatt_api.c b/stack/gatt/gatt_api.c
index b53b7c5..232b191 100644
--- a/stack/gatt/gatt_api.c
+++ b/stack/gatt/gatt_api.c
@@ -1285,6 +1285,7 @@
                     (p_clcb->p_reg->gatt_if == gatt_if) &&
                     (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
                 {
+                    btu_stop_timer(&p_clcb->rsp_timer_ent);
                     gatt_clcb_dealloc (p_clcb);
                     break;
                 }
diff --git a/stack/gatt/gatt_cl.c b/stack/gatt/gatt_cl.c
index 09ad112..e8c41fc 100644
--- a/stack/gatt/gatt_cl.c
+++ b/stack/gatt/gatt_cl.c
@@ -1093,7 +1093,7 @@
             /* dequeue the request if is write command or sign write */
             if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE)
             {
-                gatt_start_rsp_timer (p_tcb);
+                gatt_start_rsp_timer (p_cmd->clcb_idx);
             }
             else
             {
@@ -1150,7 +1150,10 @@
             return;
         }
         else
-            btu_stop_timer (&p_tcb->rsp_timer_ent);
+        {
+            btu_stop_timer (&p_clcb->rsp_timer_ent);
+            p_clcb->retry_count = 0;
+        }
     }
     /* the size of the message may not be bigger than the local max PDU size*/
     /* The message has to be smaller than the agreed MTU, len does not count op_code */
diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h
index 48278c2..1f81d63 100644
--- a/stack/gatt/gatt_int.h
+++ b/stack/gatt/gatt_int.h
@@ -78,6 +78,8 @@
 
 /* wait for ATT cmd response timeout value */
 #define GATT_WAIT_FOR_RSP_TOUT       30
+#define GATT_WAIT_FOR_DISC_RSP_TOUT  5
+#define GATT_REQ_RETRY_LIMIT         2
 
 /* characteristic descriptor type */
 #define GATT_DESCR_EXT_DSCPTOR   1    /* Characteristic Extended Properties */
@@ -360,7 +362,6 @@
     UINT8            ind_count;
 
     tGATT_CMD_Q       cl_cmd_q[GATT_CL_MAX_LCB];
-    TIMER_LIST_ENT    rsp_timer_ent;        /* peer response timer */
     TIMER_LIST_ENT    ind_ack_timer_ent;    /* local app confirm to indication timer */
     UINT8             pending_cl_req;
     UINT8             next_slot_inq;    /* index of next available slot in queue */
@@ -397,6 +398,8 @@
     BOOLEAN                 first_read_blob_after_read;
     tGATT_READ_INC_UUID128  read_uuid128;
     BOOLEAN                 in_use;
+    TIMER_LIST_ENT          rsp_timer_ent;  /* peer response timer */
+    UINT8                   retry_count;
 } tGATT_CLCB;
 
 typedef struct
@@ -556,7 +559,7 @@
 extern UINT8 gatt_build_uuid_to_stream(UINT8 **p_dst, tBT_UUID uuid);
 extern BOOLEAN gatt_uuid_compare(tBT_UUID src, tBT_UUID tar);
 extern void gatt_sr_get_sec_info(BD_ADDR rem_bda, BOOLEAN le_conn, UINT8 *p_sec_flag, UINT8 *p_key_size);
-extern void gatt_start_rsp_timer(tGATT_TCB    *p_tcb);
+extern void gatt_start_rsp_timer(UINT16 clcb_idx);
 extern void gatt_start_conf_timer(tGATT_TCB    *p_tcb);
 extern void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle);
 extern void gatt_ind_ack_timeout(TIMER_LIST_ENT *p_tle);
diff --git a/stack/gatt/gatt_utils.c b/stack/gatt/gatt_utils.c
index 7ce77eb..978c88c 100644
--- a/stack/gatt/gatt_utils.c
+++ b/stack/gatt/gatt_utils.c
@@ -1119,11 +1119,18 @@
 ** Returns          TRUE if command sent, otherwise FALSE.
 **
 *******************************************************************************/
-void gatt_start_rsp_timer(tGATT_TCB    *p_tcb)
+void gatt_start_rsp_timer(UINT16 clcb_idx)
 {
-    p_tcb->rsp_timer_ent.param  = (TIMER_PARAM_TYPE)p_tcb;
-    btu_start_timer (&p_tcb->rsp_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP,
-                     GATT_WAIT_FOR_RSP_TOUT);
+    tGATT_CLCB *p_clcb = &gatt_cb.clcb[clcb_idx];
+    UINT32 timeout = GATT_WAIT_FOR_RSP_TOUT;
+    p_clcb->rsp_timer_ent.param  = (TIMER_PARAM_TYPE)p_clcb;
+    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+        p_clcb->op_subtype == GATT_DISC_SRVC_ALL)
+    {
+        timeout = GATT_WAIT_FOR_DISC_RSP_TOUT;
+    }
+    btu_start_timer (&p_clcb->rsp_timer_ent, BTU_TTYPE_ATT_WAIT_FOR_RSP,
+                     timeout);
 }
 /*******************************************************************************
 **
@@ -1168,8 +1175,32 @@
 *******************************************************************************/
 void gatt_rsp_timeout(TIMER_LIST_ENT *p_tle)
 {
+    tGATT_CLCB *p_clcb = (tGATT_CLCB *)p_tle->param;
+    if (p_clcb == NULL || p_clcb->p_tcb == NULL)
+    {
+        GATT_TRACE_WARNING0("gatt_rsp_timeout clcb is already deleted");
+        return;
+    }
+    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
+        p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
+        p_clcb->retry_count < GATT_REQ_RETRY_LIMIT)
+    {
+        UINT8 rsp_code;
+        GATT_TRACE_WARNING0("gatt_rsp_timeout retry discovery primary service");
+        if (p_clcb != gatt_cmd_dequeue(p_clcb->p_tcb, &rsp_code))
+        {
+            GATT_TRACE_ERROR0("gatt_rsp_timeout command queue out of sync, disconnect");
+        }
+        else
+        {
+            p_clcb->retry_count++;
+            gatt_act_discovery(p_clcb);
+            return;
+        }
+    }
+
     GATT_TRACE_WARNING0("gatt_rsp_timeout disconnecting...");
-    gatt_disconnect (((tGATT_TCB *)p_tle->param)->peer_bda);
+    gatt_disconnect (p_clcb->p_tcb->peer_bda);
 }
 
 /*******************************************************************************
@@ -2077,6 +2108,7 @@
 
     operation =  p_clcb->operation;
     conn_id = p_clcb->conn_id;
+    btu_stop_timer(&p_clcb->rsp_timer_ent);
 
     gatt_clcb_dealloc(p_clcb);
 
@@ -2118,6 +2150,7 @@
             p_clcb = &gatt_cb.clcb[i];
             if (p_clcb->in_use && p_clcb->p_tcb == p_tcb)
             {
+                btu_stop_timer(&p_clcb->rsp_timer_ent);
                 GATT_TRACE_DEBUG2 ("found p_clcb conn_id=%d clcb_idx=%d", p_clcb->conn_id, p_clcb->clcb_idx);
                 if (p_clcb->operation != GATTC_OPTYPE_NONE)
                     gatt_end_operation(p_clcb, GATT_ERROR, NULL);
@@ -2127,7 +2160,6 @@
             }
         }
 
-        btu_stop_timer (&p_tcb->rsp_timer_ent);
         btu_stop_timer (&p_tcb->ind_ack_timer_ent);
         btu_stop_timer (&p_tcb->conf_timer_ent);
         gatt_free_pending_ind(p_tcb);