LE: Deep copy buffers when transfering client context

Certain BTA client event types require a deep copy of the request
data buffers when transfering context. Shallow copy of the pointers
involved may cause a crash when overlapping read and write requests
are received.

Change-Id: Id59b034d7fdd28087695a0688caff66b4cef4a4d
diff --git a/btif/include/btif_gatt_util.h b/btif/include/btif_gatt_util.h
index 37fe501..40492cc 100644
--- a/btif/include/btif_gatt_util.h
+++ b/btif/include/btif_gatt_util.h
@@ -30,6 +30,7 @@
 void bta_to_btif_char_id(btgatt_char_id_t *p_dest, tBTA_GATT_ID *p_src);
 
 uint16_t set_read_value(btgatt_read_params_t *p_dest, tBTA_GATTC_READ *p_src);
+uint16_t get_uuid16(tBT_UUID *p_uuid);
 
 void btif_gatt_check_encrypted_link(BD_ADDR bd_addr);
 void btif_gatt_remove_encrypted_link(BD_ADDR bd_addr);
diff --git a/btif/src/btif_gatt_client.c b/btif/src/btif_gatt_client.c
index ac3df52..7418f9d 100644
--- a/btif/src/btif_gatt_client.c
+++ b/btif/src/btif_gatt_client.c
@@ -39,6 +39,7 @@
 
 #if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
 
+#include "gki.h"
 #include "bta_api.h"
 #include "bta_gatt_api.h"
 #include "bd.h"
@@ -145,6 +146,72 @@
 **  Static functions
 ********************************************************************************/
 
+static void btapp_gattc_req_data(UINT16 event, char *p_dest, char *p_src)
+{
+    tBTA_GATTC *p_dest_data = (tBTA_GATTC*)p_dest;
+    tBTA_GATTC *p_src_data = (tBTA_GATTC*)p_src;
+
+    if (!p_src_data || !p_dest_data)
+       return;
+
+    // Copy basic structure first
+    memcpy(p_dest_data, p_src_data, sizeof(tBTA_GATTC));
+
+    // Allocate buffer for request data if necessary
+    switch (event)
+    {
+        case BTA_GATTC_READ_CHAR_EVT:
+        case BTA_GATTC_READ_DESCR_EVT:
+            p_dest_data->read.p_value = GKI_getbuf(sizeof(tBTA_GATT_READ_VAL));
+
+            if (p_dest_data->read.p_value != NULL)
+            {
+                memcpy(p_dest_data->read.p_value, p_src_data->read.p_value,
+                    sizeof(tBTA_GATT_READ_VAL));
+
+                // Allocate buffer for att value if necessary
+                if (get_uuid16(&p_src_data->read.descr_type) != GATT_UUID_CHAR_AGG_FORMAT
+                  && p_src_data->read.p_value->unformat.p_value != NULL)
+                {
+                    p_dest_data->read.p_value->unformat.p_value =
+                                   GKI_getbuf(p_src_data->read.p_value->unformat.len);
+                    if (p_dest_data->read.p_value->unformat.p_value != NULL)
+                    {
+                        memcpy(p_dest_data->read.p_value->unformat.p_value,
+                               p_src_data->read.p_value->unformat.p_value,
+                               p_src_data->read.p_value->unformat.len);
+                    }
+                }
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+static void btapp_gattc_free_req_data(UINT16 event, tBTA_GATTC *p_data)
+{
+    switch (event)
+    {
+        case BTA_GATTC_READ_CHAR_EVT:
+        case BTA_GATTC_READ_DESCR_EVT:
+            if (p_data != NULL && p_data->read.p_value != NULL)
+            {
+                if (get_uuid16 (&p_data->read.descr_type) != GATT_UUID_CHAR_AGG_FORMAT
+                  && p_data->read.p_value->unformat.p_value != NULL)
+                {
+                    GKI_freebuf(p_data->read.p_value->unformat.p_value);
+                }
+                GKI_freebuf(p_data->read.p_value);
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
 static void btif_gattc_init_dev_cb(void)
 {
     memset(p_dev_cb, 0, sizeof(btif_gattc_dev_cb_t));
@@ -395,12 +462,14 @@
             ALOGE("%s: Unhandled event (%d)!", __FUNCTION__, event);
             break;
     }
+
+    btapp_gattc_free_req_data(event, p_data);
 }
 
 static void bte_gattc_cback(tBTA_GATTC_EVT event, tBTA_GATTC *p_data)
 {
     bt_status_t status = btif_transfer_context(btif_gattc_upstreams_evt,
-                    (uint16_t) event, (void*)p_data, sizeof(tBTA_GATTC), NULL);
+                    (uint16_t) event, (void*)p_data, sizeof(tBTA_GATTC), btapp_gattc_req_data);
     ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
 }