diff --git a/system/bta/dm/bta_dm_act.c b/system/bta/dm/bta_dm_act.c
index 68d99d41f6c19f501562bcc9652dc1f2cb92ffed..1251f5d5baee2688e62d76e3dc4b3528aa6e7263 100644
--- a/system/bta/dm/bta_dm_act.c
+++ b/system/bta/dm/bta_dm_act.c
@@ -4755,6 +4755,24 @@ void bta_dm_ble_set_scan_rsp (tBTA_DM_MSG *p_data)
         (*p_data->ble_set_adv_data.p_adv_data_cback)(status);
 }
 
+/*******************************************************************************
+**
+** Function         bta_dm_ble_set_data_length
+**
+** Description      This function set the maximum transmission packet size
+**
+** Parameters
+**
+*******************************************************************************/
+void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data)
+{
+    if (BTM_SetBleDataLength(p_data->ble_set_data_length.remote_bda,
+                        p_data->ble_set_data_length.tx_data_length) != BTM_SUCCESS)
+    {
+        APPL_TRACE_ERROR("%s failed", __FUNCTION__);
+    }
+}
+
 /*******************************************************************************
 **
 ** Function         bta_dm_ble_broadcast
diff --git a/system/bta/dm/bta_dm_api.c b/system/bta/dm/bta_dm_api.c
index 47b9488211090394e7d93810b060ca0b4bfb8a33..9ff3e98e21298c87a7ccd112e55fced50d5cd969 100644
--- a/system/bta/dm/bta_dm_api.c
+++ b/system/bta/dm/bta_dm_api.c
@@ -1882,6 +1882,32 @@ void BTA_DmBleUpdateConnectionParams(BD_ADDR bd_addr, UINT16 min_int, UINT16 max
         bta_sys_sendmsg(p_msg);
     }
 }
+
+/*******************************************************************************
+**
+** Function         BTA_DmBleSetDataLength
+**
+** Description      This function is to set maximum LE data packet size
+**
+** Returns          void
+**
+**
+*******************************************************************************/
+void BTA_DmBleSetDataLength(BD_ADDR remote_device, UINT16 tx_data_length)
+{
+    tBTA_DM_API_BLE_SET_DATA_LENGTH *p_msg;
+
+    if ((p_msg = (tBTA_DM_API_BLE_SET_DATA_LENGTH *)GKI_getbuf(sizeof(tBTA_DM_API_BLE_SET_DATA_LENGTH)))
+                  != NULL)
+    {
+        bdcpy(p_msg->remote_bda, remote_device);
+        p_msg->hdr.event = BTA_DM_API_SET_DATA_LENGTH_EVT;
+        p_msg->tx_data_length = tx_data_length;
+
+        bta_sys_sendmsg(p_msg);
+    }
+}
+
 #endif
 
 /*******************************************************************************
diff --git a/system/bta/dm/bta_dm_int.h b/system/bta/dm/bta_dm_int.h
index 798a90975c1c684b9550b0b2dc06f2d4152e4972..cabe88eff4d70ed816c23e4d3f3cda92b945dccb 100644
--- a/system/bta/dm/bta_dm_int.h
+++ b/system/bta/dm/bta_dm_int.h
@@ -99,6 +99,7 @@ enum
     BTA_DM_API_BLE_SET_ADV_CONFIG_EVT,
     BTA_DM_API_BLE_SET_SCAN_RSP_EVT,
     BTA_DM_API_BLE_BROADCAST_EVT,
+    BTA_DM_API_SET_DATA_LENGTH_EVT,
 
 #if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
     BTA_DM_API_CFG_FILTER_COND_EVT,
@@ -466,6 +467,13 @@ typedef struct
     tBTA_DM_SEARCH_CBACK * p_cback;
 }tBTA_DM_API_BLE_OBSERVE;
 
+typedef struct
+{
+    BT_HDR      hdr;
+    BD_ADDR     remote_bda;
+    UINT16      tx_data_length;
+}tBTA_DM_API_BLE_SET_DATA_LENGTH;
+
 /* set adv parameter for BLE advertising */
 typedef struct
 {
@@ -692,6 +700,8 @@ typedef union
     tBTA_DM_API_ENABLE_SCAN_FILTER      ble_enable_scan_filt;
 #endif
     tBTA_DM_API_UPDATE_CONN_PARAM       ble_update_conn_params;
+    tBTA_DM_API_BLE_SET_DATA_LENGTH     ble_set_data_length;
+
     tBTA_DM_API_BLE_MULTI_ADV_ENB       ble_multi_adv_enb;
     tBTA_DM_API_BLE_MULTI_ADV_PARAM     ble_multi_adv_param;
     tBTA_DM_API_BLE_MULTI_ADV_DATA      ble_multi_adv_data;
@@ -1057,6 +1067,7 @@ extern void bta_dm_ble_set_adv_params (tBTA_DM_MSG *p_data);
 extern void bta_dm_ble_set_adv_config (tBTA_DM_MSG *p_data);
 extern void bta_dm_ble_set_scan_rsp (tBTA_DM_MSG *p_data);
 extern void bta_dm_ble_broadcast (tBTA_DM_MSG *p_data);
+extern void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data);
 
 #if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
 extern void bta_dm_cfg_filter_cond (tBTA_DM_MSG *p_data);
diff --git a/system/bta/dm/bta_dm_main.c b/system/bta/dm/bta_dm_main.c
index 75de1f3b2811cef945c36dc0278694204eb597ac..450151a2156e1540e786f88439ab2174de26711e 100644
--- a/system/bta/dm/bta_dm_main.c
+++ b/system/bta/dm/bta_dm_main.c
@@ -96,6 +96,7 @@ const tBTA_DM_ACTION bta_dm_action[] =
     bta_dm_ble_set_adv_config,     /* BTA_DM_API_BLE_SET_ADV_CONFIG_EVT */
     bta_dm_ble_set_scan_rsp,       /* BTA_DM_API_BLE_SET_SCAN_RSP_EVT */
     bta_dm_ble_broadcast,          /* BTA_DM_API_BLE_BROADCAST_EVT */
+    bta_dm_ble_set_data_length,    /* BTA_DM_API_SET_DATA_LENGTH_EVT */
 #if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE
     bta_dm_cfg_filter_cond,         /* BTA_DM_API_CFG_FILTER_COND_EVT */
     bta_dm_scan_filter_param_setup, /* BTA_DM_API_SCAN_FILTER_SETUP_EVT */
diff --git a/system/bta/include/bta_api.h b/system/bta/include/bta_api.h
index e6de6bb4959422f45aa99a56819af8a6aab9c124..9c13be45e984007e0d27cd4e1167d8299516e93b 100644
--- a/system/bta/include/bta_api.h
+++ b/system/bta/include/bta_api.h
@@ -2144,6 +2144,17 @@ extern void BTA_BleDisableAdvInstance(UINT8 inst_id);
 extern void BTA_DmBleUpdateConnectionParams(BD_ADDR bd_addr, UINT16 min_int,
                                    UINT16 max_int, UINT16 latency, UINT16 timeout);
 
+/*******************************************************************************
+**
+** Function         BTA_DmBleSetDataLength
+**
+** Description      This function is to set maximum LE data packet size
+**
+** Returns          void
+**
+*******************************************************************************/
+extern void BTA_DmBleSetDataLength(BD_ADDR remote_device, UINT16 tx_data_length);
+
 /*******************************************************************************
 **
 ** Function         BTA_DmBleSetStorageParams
diff --git a/system/device/include/controller.h b/system/device/include/controller.h
index af93e4742ad97fee5a588ecf0ec4148c94194c27..2acca1bc005c4fc3fdc1aa767bab79fb46535a61 100644
--- a/system/device/include/controller.h
+++ b/system/device/include/controller.h
@@ -51,6 +51,7 @@ typedef struct controller_t {
   bool (*supports_master_slave_role_switch)(void);
 
   bool (*supports_ble)(void);
+  bool (*supports_ble_packet_extension)(void);
   bool (*supports_ble_connection_parameters_request)(void);
   bool (*supports_ble_privacy)(void);
 
@@ -64,6 +65,8 @@ typedef struct controller_t {
   uint16_t (*get_acl_packet_size_classic)(void);
   uint16_t (*get_acl_packet_size_ble)(void);
 
+  uint16_t (*get_ble_default_data_packet_length)(void);
+
   // Get the number of acl packets the controller can buffer.
   uint16_t (*get_acl_buffer_count_classic)(void);
   uint8_t (*get_acl_buffer_count_ble)(void);
diff --git a/system/device/src/controller.c b/system/device/src/controller.c
index f0d3e584dff2e77a727b505ac99c5323b38a7316..02edc4fafc9412a99dbc8b93576cb4105520ada3 100644
--- a/system/device/src/controller.c
+++ b/system/device/src/controller.c
@@ -34,7 +34,8 @@
 #include "stack/include/btm_ble_api.h"
 #include "btcore/include/version.h"
 
-const bt_event_mask_t BLE_EVENT_MASK = { "\x00\x00\x00\x00\x00\x00\x00\x3f" };
+const bt_event_mask_t BLE_EVENT_MASK = { "\x00\x00\x00\x00\x00\x00\x04\x7f" };
+
 #if (BLE_INCLUDED)
 const bt_event_mask_t CLASSIC_EVENT_MASK = { HCI_DUMO_EVENT_MASK_EXT };
 #else
@@ -69,6 +70,7 @@ static uint8_t ble_white_list_size;
 static uint8_t ble_resolving_list_max_size;
 static uint8_t ble_supported_states[BLE_SUPPORTED_STATES_SIZE];
 static bt_device_features_t features_ble;
+static uint16_t ble_suggested_default_data_length;
 
 static bool readable;
 static bool ble_supported;
@@ -225,6 +227,13 @@ static future_t *start_up(void) {
             &ble_resolving_list_max_size);
     }
 
+    if (HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array)) {
+        response = AWAIT_COMMAND(packet_factory->make_ble_read_suggested_default_data_length());
+        packet_parser->parse_ble_read_suggested_default_data_length_response(
+            response,
+            &ble_suggested_default_data_length);
+    }
+
     // Set the ble event mask next
     response = AWAIT_COMMAND(packet_factory->make_ble_set_event_mask(&BLE_EVENT_MASK));
     packet_parser->parse_generic_command_complete(response);
@@ -348,6 +357,12 @@ static bool supports_ble_privacy(void) {
   return HCI_LE_ENHANCED_PRIVACY_SUPPORTED(features_ble.as_array);
 }
 
+static bool supports_ble_packet_extension(void) {
+  assert(readable);
+  assert(ble_supported);
+  return HCI_LE_DATA_LEN_EXT_SUPPORTED(features_ble.as_array);
+}
+
 static bool supports_ble_connection_parameters_request(void) {
   assert(readable);
   assert(ble_supported);
@@ -375,6 +390,12 @@ static uint16_t get_acl_packet_size_ble(void) {
   return acl_data_size_ble + HCI_DATA_PREAMBLE_SIZE;
 }
 
+static uint16_t get_ble_suggested_default_data_length(void) {
+  assert(readable);
+  assert(ble_supported);
+  return ble_suggested_default_data_length;
+}
+
 static uint16_t get_acl_buffer_count_classic(void) {
   assert(readable);
   return acl_buffer_count_classic;
@@ -420,6 +441,7 @@ static const controller_t interface = {
   supports_master_slave_role_switch,
 
   supports_ble,
+  supports_ble_packet_extension,
   supports_ble_connection_parameters_request,
   supports_ble_privacy,
 
@@ -428,6 +450,7 @@ static const controller_t interface = {
 
   get_acl_packet_size_classic,
   get_acl_packet_size_ble,
+  get_ble_suggested_default_data_length,
 
   get_acl_buffer_count_classic,
   get_acl_buffer_count_ble,
diff --git a/system/hci/include/hci_packet_factory.h b/system/hci/include/hci_packet_factory.h
index 5a50b5199b213c45ae69cc12ca2812d18ee8521f..79110e1783c58e787786850fedfb75bb05967491 100644
--- a/system/hci/include/hci_packet_factory.h
+++ b/system/hci/include/hci_packet_factory.h
@@ -38,6 +38,7 @@ typedef struct {
   BT_HDR *(*make_ble_read_supported_states)(void);
   BT_HDR *(*make_ble_read_local_supported_features)(void);
   BT_HDR *(*make_ble_read_resolving_list_size)(void);
+  BT_HDR *(*make_ble_read_suggested_default_data_length)(void);
   BT_HDR *(*make_ble_set_event_mask)(const bt_event_mask_t *event_mask);
 } hci_packet_factory_t;
 
diff --git a/system/hci/include/hci_packet_parser.h b/system/hci/include/hci_packet_parser.h
index 45b934a5dbfbf5b99cc58b82364030cf09c27cd6..57e5d1c257c990727b37f51be0b95bc319c3fe3a 100644
--- a/system/hci/include/hci_packet_parser.h
+++ b/system/hci/include/hci_packet_parser.h
@@ -87,6 +87,10 @@ typedef struct {
     uint8_t *resolving_list_size_ptr
   );
 
+  void (*parse_ble_read_suggested_default_data_length_response)(
+    BT_HDR *response,
+    uint16_t *ble_default_packet_length_ptr
+  );
 } hci_packet_parser_t;
 
 const hci_packet_parser_t *hci_packet_parser_get_interface();
diff --git a/system/hci/src/hci_packet_factory.c b/system/hci/src/hci_packet_factory.c
index 89b82d189c4bac59ed07ae9c4ad38abcd7f2e0c9..bc8fca51d16e0742552d190df9865a0312b06e98 100644
--- a/system/hci/src/hci_packet_factory.c
+++ b/system/hci/src/hci_packet_factory.c
@@ -133,6 +133,10 @@ static BT_HDR *make_ble_read_resolving_list_size(void) {
   return make_command_no_params(HCI_BLE_READ_RESOLVING_LIST_SIZE);
 }
 
+static BT_HDR *make_ble_read_suggested_default_data_length(void) {
+    return make_command_no_params(HCI_BLE_READ_DEFAULT_DATA_LENGTH);
+}
+
 static BT_HDR *make_ble_set_event_mask(const bt_event_mask_t *event_mask) {
   uint8_t *stream;
   uint8_t parameter_size = sizeof(bt_event_mask_t);
@@ -188,6 +192,7 @@ static const hci_packet_factory_t interface = {
   make_ble_read_supported_states,
   make_ble_read_local_supported_features,
   make_ble_read_resolving_list_size,
+  make_ble_read_suggested_default_data_length,
   make_ble_set_event_mask
 };
 
diff --git a/system/hci/src/hci_packet_parser.c b/system/hci/src/hci_packet_parser.c
index e25b7c479694752b0c2a8e13205a87841598357d..b9f4080cdd1dc460f3e2408ca8b9b3fc743616ab 100644
--- a/system/hci/src/hci_packet_parser.c
+++ b/system/hci/src/hci_packet_parser.c
@@ -173,6 +173,16 @@ static void parse_ble_read_resolving_list_size_response(
   buffer_allocator->free(response);
 }
 
+static void parse_ble_read_suggested_default_data_length_response(
+    BT_HDR *response,
+    uint16_t *ble_default_packet_length_ptr) {
+
+  uint8_t *stream = read_command_complete_header(response, HCI_BLE_READ_DEFAULT_DATA_LENGTH, 2 /* bytes after */);
+  STREAM_TO_UINT8(*ble_default_packet_length_ptr, stream);
+
+  buffer_allocator->free(response);
+}
+
 // Internal functions
 
 static uint8_t *read_command_complete_header(
@@ -225,7 +235,8 @@ static const hci_packet_parser_t interface = {
   parse_ble_read_buffer_size_response,
   parse_ble_read_supported_states_response,
   parse_ble_read_local_supported_features_response,
-  parse_ble_read_resolving_list_size_response
+  parse_ble_read_resolving_list_size_response,
+  parse_ble_read_suggested_default_data_length_response
 };
 
 const hci_packet_parser_t *hci_packet_parser_get_interface() {
diff --git a/system/stack/btm/btm_ble.c b/system/stack/btm/btm_ble.c
index e492b1f3bcc0997d9d3be17dbdee61e9a8adc33c..789cfb1e60eb7974cea4ff687ada963be4a07918 100644
--- a/system/stack/btm/btm_ble.c
+++ b/system/stack/btm/btm_ble.c
@@ -38,6 +38,7 @@
 #include "gap_api.h"
 #include "bt_utils.h"
 #include "device/include/controller.h"
+
 #define LOG_TAG "bt_btm_ble"
 #include "osi/include/log.h"
 
@@ -759,6 +760,54 @@ BOOLEAN BTM_UseLeLink (BD_ADDR bd_addr)
     }
     return use_le;
 }
+
+
+/*******************************************************************************
+**
+** Function         BTM_SetBleDataLength
+**
+** Description      This function is to set maximum BLE transmission packet size
+**
+** Returns          BTM_SUCCESS if success; otherwise failed.
+**
+*******************************************************************************/
+tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length)
+{
+    tACL_CONN *p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
+    BTM_TRACE_DEBUG("%s: tx_pdu_length =%d", __FUNCTION__, tx_pdu_length);
+
+    if (!controller_get_interface()->supports_ble_packet_extension())
+    {
+        BTM_TRACE_ERROR("%s failed, request not supported", __FUNCTION__);
+        return BTM_ILLEGAL_VALUE;
+    }
+
+    if (!HCI_LE_DATA_LEN_EXT_SUPPORTED(p_acl->peer_le_features))
+    {
+        BTM_TRACE_ERROR("%s failed, peer does not support request", __FUNCTION__);
+        return BTM_ILLEGAL_VALUE;
+    }
+
+    if (p_acl != NULL)
+    {
+        if (tx_pdu_length > BTM_BLE_DATA_SIZE_MAX)
+            tx_pdu_length =  BTM_BLE_DATA_SIZE_MAX;
+        else if (tx_pdu_length < BTM_BLE_DATA_SIZE_MIN)
+            tx_pdu_length =  BTM_BLE_DATA_SIZE_MIN;
+
+        /* always set the TxTime to be max, as controller does not care for now */
+        btsnd_hcic_ble_set_data_length(p_acl->hci_handle, tx_pdu_length,
+                                            BTM_BLE_DATA_TX_TIME_MAX);
+
+        return BTM_SUCCESS;
+    }
+    else
+    {
+        BTM_TRACE_ERROR("%s: Wrong mode: no LE link exist or LE not supported",__FUNCTION__);
+        return BTM_WRONG_MODE;
+    }
+}
+
 /*******************************************************************************
 **
 ** Function         btm_ble_rand_enc_complete
diff --git a/system/stack/btu/btu_hcif.c b/system/stack/btu/btu_hcif.c
index e3f61398c449d5ed3788af08ffaaaf0612af62fe..7005772714a888bc2a7ec283ac7c92dc9b0926b3 100644
--- a/system/stack/btu/btu_hcif.c
+++ b/system/stack/btu/btu_hcif.c
@@ -40,7 +40,8 @@
 #include "btm_api.h"
 #include "btm_int.h"
 #include "bt_utils.h"
-#include "osi/include/osi.h"
+#include "device/include/controller.h"
+#include "osi.h"
 #include "osi/include/log.h"
 #include "hci_layer.h"
 
@@ -119,6 +120,7 @@ static void btu_ble_read_remote_feat_evt (UINT8 *p);
 static void btu_ble_ll_conn_param_upd_evt (UINT8 *p, UINT16 evt_len);
 static void btu_ble_proc_ltk_req (UINT8 *p);
 static void btu_hcif_encryption_key_refresh_cmpl_evt (UINT8 *p);
+static void btu_ble_data_length_change_evt (UINT8 *p, UINT16 evt_len);
 #if (BLE_LLT_INCLUDED == TRUE)
 static void btu_ble_rc_param_req_evt(UINT8 *p);
 #endif
@@ -332,7 +334,9 @@ void btu_hcif_process_event (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_msg)
                     btu_ble_rc_param_req_evt(p);
                     break;
 #endif
-
+               case HCI_BLE_DATA_LENGTH_CHANGE_EVT:
+                    btu_ble_data_length_change_evt(p, hci_evt_len);
+                    break;
             }
             break;
 #endif /* BLE_INCLUDED */
@@ -1721,6 +1725,27 @@ static void btu_ble_proc_ltk_req (UINT8 *p)
 #endif
     /* This is empty until an upper layer cares about returning event */
 }
+
+static void btu_ble_data_length_change_evt(UINT8 *p, UINT16 evt_len)
+{
+    UINT16 handle;
+    UINT16 tx_data_len;
+    UINT16 rx_data_len;
+
+    if (!controller_get_interface()->supports_ble_packet_extension())
+    {
+        HCI_TRACE_WARNING("%s, request not supported", __FUNCTION__);
+        return;
+    }
+
+    STREAM_TO_UINT16(handle, p);
+    STREAM_TO_UINT16(tx_data_len, p);
+    p += 2; /* Skip the TxTimer */
+    STREAM_TO_UINT16(rx_data_len, p);
+
+    l2cble_process_data_length_change_event(handle, tx_data_len, rx_data_len);
+}
+
 /**********************************************
 ** End of BLE Events Handler
 ***********************************************/
diff --git a/system/stack/gatt/gatt_cl.c b/system/stack/gatt/gatt_cl.c
index 0578086bb19fc1c520c1d5b7053a7f7b52c2207e..3e623bf7bb932035a22a35667ce6778afa63659e 100644
--- a/system/stack/gatt/gatt_cl.c
+++ b/system/stack/gatt/gatt_cl.c
@@ -30,6 +30,7 @@
 #include "bt_utils.h"
 #include "gki.h"
 #include "gatt_int.h"
+#include "l2c_int.h"
 
 #define GATT_WRITE_LONG_HDR_SIZE    5 /* 1 opcode + 2 handle + 2 offset */
 #define GATT_READ_CHAR_VALUE_HDL    (GATT_READ_CHAR_VALUE | 0x80)
@@ -1065,6 +1066,7 @@ void gatt_process_mtu_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT
         p_tcb->payload_size = mtu;
     }
 
+    l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID, p_tcb->payload_size);
     gatt_end_operation(p_clcb, status, NULL);
 }
 /*******************************************************************************
diff --git a/system/stack/gatt/gatt_sr.c b/system/stack/gatt/gatt_sr.c
old mode 100755
new mode 100644
index d4323c74badd7a023cbc4681a1ddf99796e071e0..05facd60677be4dff893e456392adfb27f6e4653
--- a/system/stack/gatt/gatt_sr.c
+++ b/system/stack/gatt/gatt_sr.c
@@ -29,7 +29,7 @@
 #include <string.h>
 #include "gatt_int.h"
 #include "l2c_api.h"
-
+#include "l2c_int.h"
 #define GATT_MTU_REQ_MIN_LEN        2
 
 
@@ -935,6 +935,8 @@ static void gatts_process_mtu_req (tGATT_TCB *p_tcb, UINT16 len, UINT8 *p_data)
 
         GATT_TRACE_ERROR("MTU request PDU with MTU size %d", p_tcb->payload_size);
 
+        l2cble_set_fixed_channel_tx_data_length(p_tcb->peer_bda, L2CAP_ATT_CID, p_tcb->payload_size);
+
         if ((p_buf = attp_build_sr_msg(p_tcb, GATT_RSP_MTU, (tGATT_SR_MSG *) &p_tcb->payload_size)) != NULL)
         {
             attp_send_sr_msg (p_tcb, p_buf);
diff --git a/system/stack/hcic/hciblecmds.c b/system/stack/hcic/hciblecmds.c
index 9a5e1069d31b1cf45cb7ad154b0559eb44bfb110..5d7d2106b2a3d66ebfa3f1f6ff1b09e899c9721a 100644
--- a/system/stack/hcic/hciblecmds.c
+++ b/system/stack/hcic/hciblecmds.c
@@ -929,6 +929,29 @@ BOOLEAN btsnd_hcic_ble_set_rand_priv_addr_timeout (UINT16 rpa_timout)
     return (TRUE);
 }
 
+BOOLEAN btsnd_hcic_ble_set_data_length(UINT16 conn_handle, UINT16 tx_octets, UINT16 tx_time)
+{
+    BT_HDR *p;
+    UINT8 *pp;
+
+    if ((p = HCI_GET_CMD_BUF(HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH)) == NULL)
+        return FALSE;
+
+    pp = p->data;
+
+    p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH;
+    p->offset = 0;
+
+    UINT16_TO_STREAM(pp, HCI_BLE_SET_DATA_LENGTH);
+    UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH);
+
+    UINT16_TO_STREAM(pp, conn_handle);
+    UINT16_TO_STREAM(pp, tx_octets);
+    UINT16_TO_STREAM(pp, tx_time);
+
+    btu_hcif_send_cmd (LOCAL_BR_EDR_CONTROLLER_ID, p);
+    return TRUE;
+}
 
 #endif
 
diff --git a/system/stack/include/btm_ble_api.h b/system/stack/include/btm_ble_api.h
index 607e6871e257d376aec159a9c47cd208f5ea7ffd..df61449d987ef2a21868d98fbb63f3eb6b6a24d4 100644
--- a/system/stack/include/btm_ble_api.h
+++ b/system/stack/include/btm_ble_api.h
@@ -327,10 +327,21 @@ typedef  UINT32  tBTM_BLE_AD_MASK;
 #define BTM_BLE_AD_TYPE_MANU            HCI_EIR_MANUFACTURER_SPECIFIC_TYPE      /* 0xff */
 typedef UINT8   tBTM_BLE_AD_TYPE;
 
-/* security settings used with L2CAP LE COC */
+/*  Security settings used with L2CAP LE COC */
 #define BTM_SEC_LE_LINK_ENCRYPTED           0x01
 #define BTM_SEC_LE_LINK_PAIRED_WITHOUT_MITM 0x02
 #define BTM_SEC_LE_LINK_PAIRED_WITH_MITM    0x04
+
+/*  Min/max Preferred  number of payload octets that the local Controller
+    should include in a single Link Layer Data Channel PDU. */
+#define BTM_BLE_DATA_SIZE_MAX     0x00fb
+#define BTM_BLE_DATA_SIZE_MIN     0x001b
+
+/*  Preferred maximum number of microseconds that the local Controller
+    should use to transmit a single Link Layer Data Channel PDU. */
+#define BTM_BLE_DATA_TX_TIME_MIN     0x0148
+#define BTM_BLE_DATA_TX_TIME_MAX     0x0848
+
 /* adv tx power level */
 #define BTM_BLE_ADV_TX_POWER_MIN        0           /* minimum tx power */
 #define BTM_BLE_ADV_TX_POWER_LOW        1           /* low tx power     */
@@ -1765,6 +1776,17 @@ extern tBTM_STATUS BTM_BleEnableDisableFilterFeature(UINT8 enable,
 *******************************************************************************/
 extern tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK *p_ener_cback);
 
+/*******************************************************************************
+**
+** Function         BTM_SetBleDataLength
+**
+** Description      This function is called to set maximum BLE transmission packet size
+**
+** Returns          BTM_SUCCESS if success; otherwise failed.
+**
+*******************************************************************************/
+extern tBTM_STATUS BTM_SetBleDataLength(BD_ADDR bd_addr, UINT16 tx_pdu_length);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/system/stack/include/hcidefs.h b/system/stack/include/hcidefs.h
index 92d9d844eeff1c3f870eb62bcbfb05c21112cf2a..04c5ed66527e83a3bb10b16337801658694e77ff 100644
--- a/system/stack/include/hcidefs.h
+++ b/system/stack/include/hcidefs.h
@@ -333,6 +333,10 @@
 #define HCI_BLE_RC_PARAM_REQ_REPLY      (0x0020 | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_RC_PARAM_REQ_NEG_REPLY  (0x0021 | HCI_GRP_BLE_CMDS)
 
+#define HCI_BLE_SET_DATA_LENGTH             (0x0022 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_READ_DEFAULT_DATA_LENGTH    (0x0023 | HCI_GRP_BLE_CMDS)
+#define HCI_BLE_WRITE_DEFAULT_DATA_LENGTH   (0x0024 | HCI_GRP_BLE_CMDS)
+
 #define HCI_BLE_ADD_DEV_RESOLVING_LIST      (0x0027 | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_RM_DEV_RESOLVING_LIST       (0x0028 | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_CLEAR_RESOLVING_LIST        (0x0029 | HCI_GRP_BLE_CMDS)
@@ -342,7 +346,6 @@
 #define HCI_BLE_SET_ADDR_RESOLUTION_ENABLE  (0x002D | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT   (0x002E | HCI_GRP_BLE_CMDS)
 
-
 /* LE Get Vendor Capabilities Command OCF */
 #define HCI_BLE_VENDOR_CAP_OCF    (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
 
@@ -1757,12 +1760,16 @@ typedef struct
 #define HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF        0
 #define HCI_LE_ENHANCED_PRIVACY_SUPPORTED(x) ((x)[HCI_LE_FEATURE_ENHANCED_PRIVACY_OFF] & HCI_LE_FEATURE_ENHANCED_PRIVACY_MASK)
 
-
 /* Extended scanner filter policy : 7 */
 #define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK       0x80
 #define HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF        0
 #define HCI_LE_EXT_SCAN_FILTER_POLICY_SUPPORTED(x) ((x)[HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_OFF] & HCI_LE_FEATURE_EXT_SCAN_FILTER_POLICY_MASK)
 
+/* Slave-initiated Features Exchange */
+#define HCI_LE_FEATURE_DATA_LEN_EXT_MASK       0x20
+#define HCI_LE_FEATURE_DATA_LEN_EXT_OFF        0
+#define HCI_LE_DATA_LEN_EXT_SUPPORTED(x) ((x)[HCI_LE_FEATURE_DATA_LEN_EXT_OFF] & HCI_LE_FEATURE_DATA_LEN_EXT_MASK)
+
 /*
 **   Local Supported Commands encoding
 */
diff --git a/system/stack/include/hcimsgs.h b/system/stack/include/hcimsgs.h
index dfc0d50cb0a32b3d059019bba390220ea9123ae9..672f5fb4cdd8845a9873fe804e6cba4e47aea36a 100644
--- a/system/stack/include/hcimsgs.h
+++ b/system/stack/include/hcimsgs.h
@@ -661,13 +661,13 @@ extern void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode,
 #define HCIC_PARAM_SIZE_BLE_READ_REMOTE_FEAT    2
 #define HCIC_PARAM_SIZE_BLE_ENCRYPT             32
 #define HCIC_PARAM_SIZE_BLE_RAND                0
-#define HCIC_PARAM_SIZE_WRITE_LE_HOST_SUPPORTED	2
+#define HCIC_PARAM_SIZE_WRITE_LE_HOST_SUPPORTED 2
 
 #define HCIC_BLE_RAND_DI_SIZE                   8
 #define HCIC_BLE_ENCRYT_KEY_SIZE                16
 #define HCIC_PARAM_SIZE_BLE_START_ENC           (4 + HCIC_BLE_RAND_DI_SIZE + HCIC_BLE_ENCRYT_KEY_SIZE)
 #define HCIC_PARAM_SIZE_LTK_REQ_REPLY           (2 + HCIC_BLE_ENCRYT_KEY_SIZE)
-#define HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY           2
+#define HCIC_PARAM_SIZE_LTK_REQ_NEG_REPLY       2
 #define HCIC_BLE_CHNL_MAP_SIZE                  5
 #define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA      31
 
@@ -679,6 +679,7 @@ extern void btsnd_hcic_vendor_spec_cmd (void *buffer, UINT16 opcode,
 #define HCIC_PARAM_SIZE_BLE_READ_RESOLVABLE_ADDR_LOCAL  7
 #define HCIC_PARAM_SIZE_BLE_SET_ADDR_RESOLUTION_ENABLE  1
 #define HCIC_PARAM_SIZE_BLE_SET_RAND_PRIV_ADDR_TIMOUT   2
+#define HCIC_PARAM_SIZE_BLE_SET_DATA_LENGTH             6
 
 /* ULP HCI command */
 extern BOOLEAN btsnd_hcic_ble_set_evt_mask (BT_EVENT_MASK event_mask);
@@ -771,6 +772,8 @@ extern BOOLEAN btsnd_hcic_ble_rc_param_req_neg_reply(UINT16 handle, UINT8 reason
 
 #endif /* BLE_LLT_INCLUDED */
 
+extern BOOLEAN btsnd_hcic_ble_set_data_length(UINT16 conn_handle, UINT16 tx_octets,
+                                                      UINT16 tx_time);
 
 extern BOOLEAN btsnd_hcic_ble_add_device_resolving_list (UINT8 addr_type_peer,
                                                                BD_ADDR bda_peer,
diff --git a/system/stack/l2cap/l2c_ble.c b/system/stack/l2cap/l2c_ble.c
index 94ddf4268ecc0a7775c5609e352db42c980e0282..05ff5bf4097b80c5748be8e766bee2ed1865e560 100644
--- a/system/stack/l2cap/l2c_ble.c
+++ b/system/stack/l2cap/l2c_ble.c
@@ -985,5 +985,103 @@ void l2cble_process_rc_param_request_evt(UINT16 handle, UINT16 int_min, UINT16 i
 }
 #endif
 
+/*******************************************************************************
+**
+** Function         l2cble_update_data_length
+**
+** Description      This function update link tx data length if applicable
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_update_data_length(tL2C_LCB *p_lcb)
+{
+    UINT16 tx_mtu = 0;
+    UINT16 i = 0;
+
+    L2CAP_TRACE_DEBUG("%s", __FUNCTION__);
+
+    /* See if we have a link control block for the connection */
+    if (p_lcb == NULL)
+        return;
+
+    for (i = 0; i < L2CAP_NUM_FIXED_CHNLS; i++)
+    {
+        if (i + L2CAP_FIRST_FIXED_CHNL != L2CAP_BLE_SIGNALLING_CID)
+        {
+            if ((p_lcb->p_fixed_ccbs[i] != NULL) &&
+                    (tx_mtu < (p_lcb->p_fixed_ccbs[i]->tx_data_len + L2CAP_PKT_OVERHEAD)))
+                tx_mtu = p_lcb->p_fixed_ccbs[i]->tx_data_len + L2CAP_PKT_OVERHEAD;
+        }
+    }
+
+    if (tx_mtu > BTM_BLE_DATA_SIZE_MAX)
+        tx_mtu = BTM_BLE_DATA_SIZE_MAX;
+
+    /* update TX data length if changed */
+    if (p_lcb->tx_data_len != tx_mtu)
+        BTM_SetBleDataLength(p_lcb->remote_bd_addr, tx_mtu);
+
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_process_data_length_change_evt
+**
+** Description      This function process the data length change event
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_process_data_length_change_event(UINT16 handle, UINT16 tx_data_len, UINT16 rx_data_len)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_handle(handle);
+
+    L2CAP_TRACE_DEBUG("%s TX data len = %d", __FUNCTION__, tx_data_len);
+    if (p_lcb == NULL)
+        return;
+
+    if (tx_data_len > 0)
+        p_lcb->tx_data_len = tx_data_len;
+
+    /* ignore rx_data len for now */
+}
+
+/*******************************************************************************
+**
+** Function         l2cble_set_fixed_channel_tx_data_length
+**
+** Description      This function update max fixed channel tx data length if applicable
+**
+** Returns          void
+**
+*******************************************************************************/
+void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda, UINT16 fix_cid, UINT16 tx_mtu)
+{
+    tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(remote_bda, BT_TRANSPORT_LE);
+    UINT16 cid = fix_cid - L2CAP_FIRST_FIXED_CHNL;
+
+    L2CAP_TRACE_DEBUG("%s TX MTU = %d", __FUNCTION__, tx_mtu);
+
+    if (!controller_get_interface()->supports_ble_packet_extension())
+    {
+        L2CAP_TRACE_WARNING("%s, request not supported", __FUNCTION__);
+        return;
+    }
+
+    /* See if we have a link control block for the connection */
+    if (p_lcb == NULL)
+        return;
+
+    if (p_lcb->p_fixed_ccbs[cid] != NULL)
+    {
+        if (tx_mtu > BTM_BLE_DATA_SIZE_MAX)
+            tx_mtu = BTM_BLE_DATA_SIZE_MAX;
+
+        p_lcb->p_fixed_ccbs[cid]->tx_data_len = tx_mtu;
+    }
+
+    l2cble_update_data_length(p_lcb);
+}
 
 #endif /* (BLE_INCLUDED == TRUE) */
diff --git a/system/stack/l2cap/l2c_int.h b/system/stack/l2cap/l2c_int.h
index 08c4ea10ef14e9643b660afbef5c4f88a60b6690..cbaca825176478642c13e2432a31d055e5f85907 100644
--- a/system/stack/l2cap/l2c_int.h
+++ b/system/stack/l2cap/l2c_int.h
@@ -313,7 +313,7 @@ typedef struct t_l2c_ccb
 #if (L2CAP_NUM_FIXED_CHNLS > 0) || (L2CAP_UCD_INCLUDED == TRUE)
     UINT16              fixed_chnl_idle_tout;   /* Idle timeout to use for the fixed channel       */
 #endif
-
+    UINT16              tx_data_len;
 } tL2C_CCB;
 
 /***********************************************************************
@@ -403,6 +403,7 @@ typedef struct t_l2c_linkcb
     tBT_TRANSPORT       transport;
 #if (BLE_INCLUDED == TRUE)
     tBLE_ADDR_TYPE      ble_addr_type;
+    UINT16              tx_data_len;            /* tx data length used in data length extension */
 
 #define L2C_BLE_CONN_UPDATE_DISABLE 0x1  /* disable update connection parameters */
 #define L2C_BLE_NEW_CONN_PARAM      0x2  /* new connection parameter to be set */
@@ -744,6 +745,13 @@ extern void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status);
 extern void l2cble_process_rc_param_request_evt(UINT16 handle, UINT16 int_min, UINT16 int_max,
                                                         UINT16 latency, UINT16 timeout);
 #endif
+
+extern void l2cble_update_data_length(tL2C_LCB *p_lcb);
+extern void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda, UINT16 fix_cid,
+                                                                UINT16 tx_mtu);
+extern void l2cble_process_data_length_change_event(UINT16 handle, UINT16 tx_data_len,
+                                                                UINT16 rx_data_len);
+
 #endif
 extern void l2cu_process_fixed_disc_cback (tL2C_LCB *p_lcb);
 
diff --git a/system/stack/l2cap/l2c_utils.c b/system/stack/l2cap/l2c_utils.c
index d3ee908f2f0158a0c4b2ced137e1cb182e23e2ff..e80d16b0f2712dd0cf7610525c706b04cb43d4ad 100644
--- a/system/stack/l2cap/l2c_utils.c
+++ b/system/stack/l2cap/l2c_utils.c
@@ -74,6 +74,7 @@ tL2C_LCB *l2cu_allocate_lcb (BD_ADDR p_bd_addr, BOOLEAN is_bonding, tBT_TRANSPOR
             p_lcb->is_bonding      = is_bonding;
 #if (BLE_INCLUDED == TRUE)
             p_lcb->transport       = transport;
+            p_lcb->tx_data_len     = controller_get_interface()->get_ble_default_data_packet_length();
 
             if (transport == BT_TRANSPORT_LE)
             {