Bluetooth: Set local_amp_id after getting Phylink Completed evt
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / bluetooth / l2cap_core.c
index 22f3768aa0be786377f5546023ede245ed9cf47e..7114bdff595896ac8ce88f617c29fbad4e66d36b 100644 (file)
@@ -38,6 +38,7 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
 #include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
 
 bool disable_ertm;
 
@@ -577,6 +578,13 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
                        mgr->bredr_chan = NULL;
        }
 
+       if (chan->hs_hchan) {
+               struct hci_chan *hs_hchan = chan->hs_hchan;
+
+               BT_DBG("chan %p disconnect hs_hchan %p", chan, hs_hchan);
+               amp_disconnect_logical_link(hs_hchan);
+       }
+
        chan->ops->teardown(chan, err);
 
        if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
@@ -947,6 +955,9 @@ static void l2cap_send_sframe(struct l2cap_chan *chan,
        if (!control->sframe)
                return;
 
+       if (__chan_is_moving(chan))
+               return;
+
        if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) &&
            !control->poll)
                control->final = 1;
@@ -1010,6 +1021,12 @@ static bool __amp_capable(struct l2cap_chan *chan)
                return false;
 }
 
+static bool l2cap_check_efs(struct l2cap_chan *chan)
+{
+       /* Check EFS parameters */
+       return true;
+}
+
 void l2cap_send_conn_req(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
@@ -1811,6 +1828,9 @@ static void l2cap_streaming_send(struct l2cap_chan *chan,
 
        BT_DBG("chan %p, skbs %p", chan, skbs);
 
+       if (__chan_is_moving(chan))
+               return;
+
        skb_queue_splice_tail_init(skbs, &chan->tx_q);
 
        while (!skb_queue_empty(&chan->tx_q)) {
@@ -1853,6 +1873,9 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
        if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
                return 0;
 
+       if (__chan_is_moving(chan))
+               return 0;
+
        while (chan->tx_send_head &&
               chan->unacked_frames < chan->remote_tx_win &&
               chan->tx_state == L2CAP_TX_STATE_XMIT) {
@@ -1918,6 +1941,9 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
        if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
                return;
 
+       if (__chan_is_moving(chan))
+               return;
+
        while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) {
                seq = l2cap_seq_list_pop(&chan->retrans_list);
 
@@ -2260,7 +2286,9 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
        /* PDU size is derived from the HCI MTU */
        pdu_len = chan->conn->mtu;
 
-       pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
+       /* Constrain PDU size for BR/EDR connections */
+       if (!chan->hs_hcon)
+               pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
 
        /* Adjust for largest possible L2CAP overhead. */
        if (chan->fcs)
@@ -2955,6 +2983,44 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
        return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
 }
 
+static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan,
+                                     struct l2cap_conf_rfc *rfc)
+{
+       if (chan->local_amp_id && chan->hs_hcon) {
+               u64 ertm_to = chan->hs_hcon->hdev->amp_be_flush_to;
+
+               /* Class 1 devices have must have ERTM timeouts
+                * exceeding the Link Supervision Timeout.  The
+                * default Link Supervision Timeout for AMP
+                * controllers is 10 seconds.
+                *
+                * Class 1 devices use 0xffffffff for their
+                * best-effort flush timeout, so the clamping logic
+                * will result in a timeout that meets the above
+                * requirement.  ERTM timeouts are 16-bit values, so
+                * the maximum timeout is 65.535 seconds.
+                */
+
+               /* Convert timeout to milliseconds and round */
+               ertm_to = DIV_ROUND_UP_ULL(ertm_to, 1000);
+
+               /* This is the recommended formula for class 2 devices
+                * that start ERTM timers when packets are sent to the
+                * controller.
+                */
+               ertm_to = 3 * ertm_to + 500;
+
+               if (ertm_to > 0xffff)
+                       ertm_to = 0xffff;
+
+               rfc->retrans_timeout = cpu_to_le16((u16) ertm_to);
+               rfc->monitor_timeout = rfc->retrans_timeout;
+       } else {
+               rfc->retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+               rfc->monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+       }
+}
+
 static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
 {
        if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
@@ -3021,8 +3087,8 @@ done:
        case L2CAP_MODE_ERTM:
                rfc.mode            = L2CAP_MODE_ERTM;
                rfc.max_transmit    = chan->max_tx;
-               rfc.retrans_timeout = 0;
-               rfc.monitor_timeout = 0;
+
+               __l2cap_set_ertm_timeouts(chan, &rfc);
 
                size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
                             L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE -
@@ -3250,10 +3316,7 @@ done:
                        rfc.max_pdu_size = cpu_to_le16(size);
                        chan->remote_mps = size;
 
-                       rfc.retrans_timeout =
-                               __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
-                       rfc.monitor_timeout =
-                               __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+                       __l2cap_set_ertm_timeouts(chan, &rfc);
 
                        set_bit(CONF_MODE_DONE, &chan->conf_state);
 
@@ -3429,12 +3492,21 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
        struct l2cap_conn_rsp rsp;
        struct l2cap_conn *conn = chan->conn;
        u8 buf[128];
+       u8 rsp_code;
 
        rsp.scid   = cpu_to_le16(chan->dcid);
        rsp.dcid   = cpu_to_le16(chan->scid);
        rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
        rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
-       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+       if (chan->hs_hcon)
+               rsp_code = L2CAP_CREATE_CHAN_RSP;
+       else
+               rsp_code = L2CAP_CONN_RSP;
+
+       BT_DBG("chan %p rsp_code %u", chan, rsp_code);
+
+       l2cap_send_cmd(conn, chan->ident, rsp_code, sizeof(rsp), &rsp);
 
        if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
                return;
@@ -3849,7 +3921,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
                /* check compatibility */
 
                /* Send rsp for BR/EDR channel */
-               if (!chan->ctrl_id)
+               if (!chan->hs_hcon)
                        l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags);
                else
                        chan->ident = cmd->ident;
@@ -3899,13 +3971,15 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
                                goto done;
                        }
 
-                       /* check compatibility */
-
-                       if (!chan->ctrl_id)
+                       if (!chan->hs_hcon) {
                                l2cap_send_efs_conf_rsp(chan, buf, cmd->ident,
                                                        0);
-                       else
-                               chan->ident = cmd->ident;
+                       } else {
+                               if (l2cap_check_efs(chan)) {
+                                       amp_create_logical_link(chan);
+                                       chan->ident = cmd->ident;
+                               }
+                       }
                }
                goto done;
 
@@ -4163,7 +4237,9 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
                                    u16 cmd_len, void *data)
 {
        struct l2cap_create_chan_req *req = data;
+       struct l2cap_create_chan_rsp rsp;
        struct l2cap_chan *chan;
+       struct hci_dev *hdev;
        u16 psm, scid;
 
        if (cmd_len != sizeof(*req))
@@ -4177,36 +4253,56 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
 
        BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id);
 
-       if (req->amp_id) {
-               struct hci_dev *hdev;
-
-               /* Validate AMP controller id */
-               hdev = hci_dev_get(req->amp_id);
-               if (!hdev || hdev->dev_type != HCI_AMP ||
-                   !test_bit(HCI_UP, &hdev->flags)) {
-                       struct l2cap_create_chan_rsp rsp;
+       /* For controller id 0 make BR/EDR connection */
+       if (req->amp_id == HCI_BREDR_ID) {
+               l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
+                             req->amp_id);
+               return 0;
+       }
 
-                       rsp.dcid = 0;
-                       rsp.scid = cpu_to_le16(scid);
-                       rsp.result = __constant_cpu_to_le16(L2CAP_CR_BAD_AMP);
-                       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
+       /* Validate AMP controller id */
+       hdev = hci_dev_get(req->amp_id);
+       if (!hdev)
+               goto error;
 
-                       l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
-                                      sizeof(rsp), &rsp);
+       if (hdev->dev_type != HCI_AMP || !test_bit(HCI_UP, &hdev->flags)) {
+               hci_dev_put(hdev);
+               goto error;
+       }
 
-                       if (hdev)
-                               hci_dev_put(hdev);
+       chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
+                            req->amp_id);
+       if (chan) {
+               struct amp_mgr *mgr = conn->hcon->amp_mgr;
+               struct hci_conn *hs_hcon;
 
-                       return 0;
+               hs_hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, conn->dst);
+               if (!hs_hcon) {
+                       hci_dev_put(hdev);
+                       return -EFAULT;
                }
 
-               hci_dev_put(hdev);
+               BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon);
+
+               mgr->bredr_chan = chan;
+               chan->hs_hcon = hs_hcon;
+               conn->mtu = hdev->block_mtu;
        }
 
-       chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
-                            req->amp_id);
+       hci_dev_put(hdev);
 
        return 0;
+
+error:
+       rsp.dcid = 0;
+       rsp.scid = cpu_to_le16(scid);
+       rsp.result = __constant_cpu_to_le16(L2CAP_CR_BAD_AMP);
+       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
+
+       l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
+                      sizeof(rsp), &rsp);
+
+       return -EFAULT;
 }
 
 static void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id)
@@ -4325,19 +4421,14 @@ static void l2cap_logical_finish_create(struct l2cap_chan *chan,
                                        struct hci_chan *hchan)
 {
        struct l2cap_conf_rsp rsp;
-       u8 code;
 
-       chan->hs_hcon = hchan->conn;
+       chan->hs_hchan = hchan;
        chan->hs_hcon->l2cap_data = chan->conn;
 
-       code = l2cap_build_conf_rsp(chan, &rsp,
-                                   L2CAP_CONF_SUCCESS, 0);
-       l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CONF_RSP, code,
-                      &rsp);
-       set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+       l2cap_send_efs_conf_rsp(chan, &rsp, chan->ident, 0);
 
        if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
-               int err = 0;
+               int err;
 
                set_default_fcs(chan);
 
@@ -4384,8 +4475,8 @@ static void l2cap_logical_finish_move(struct l2cap_chan *chan,
 }
 
 /* Call with chan locked */
-static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
-                             u8 status)
+void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
+                      u8 status)
 {
        BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status);
 
@@ -4404,24 +4495,61 @@ static void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
        }
 }
 
+void l2cap_move_start(struct l2cap_chan *chan)
+{
+       BT_DBG("chan %p", chan);
+
+       if (chan->local_amp_id == HCI_BREDR_ID) {
+               if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED)
+                       return;
+               chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
+               chan->move_state = L2CAP_MOVE_WAIT_PREPARE;
+               /* Placeholder - start physical link setup */
+       } else {
+               chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
+               chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
+               chan->move_id = 0;
+               l2cap_move_setup(chan);
+               l2cap_send_move_chan_req(chan, 0);
+       }
+}
+
 static void l2cap_do_create(struct l2cap_chan *chan, int result,
                            u8 local_amp_id, u8 remote_amp_id)
 {
-       if (!test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
+       BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state),
+              local_amp_id, remote_amp_id);
+
+       chan->fcs = L2CAP_FCS_NONE;
+
+       /* Outgoing channel on AMP */
+       if (chan->state == BT_CONNECT) {
+               if (result == L2CAP_CR_SUCCESS) {
+                       chan->local_amp_id = local_amp_id;
+                       l2cap_send_create_chan_req(chan, remote_amp_id);
+               } else {
+                       /* Revert to BR/EDR connect */
+                       l2cap_send_conn_req(chan);
+               }
+
+               return;
+       }
+
+       /* Incoming channel on AMP */
+       if (__l2cap_no_conn_pending(chan)) {
                struct l2cap_conn_rsp rsp;
                char buf[128];
                rsp.scid = cpu_to_le16(chan->dcid);
                rsp.dcid = cpu_to_le16(chan->scid);
 
-               /* Incoming channel on AMP */
                if (result == L2CAP_CR_SUCCESS) {
                        /* Send successful response */
-                       rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
-                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                       rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
+                       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
                } else {
                        /* Send negative response */
-                       rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM);
-                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                       rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
+                       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
                }
 
                l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP,
@@ -4435,15 +4563,6 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
                                       l2cap_build_conf_req(chan, buf), buf);
                        chan->num_conf_req++;
                }
-       } else {
-               /* Outgoing channel on AMP */
-               if (result == L2CAP_CR_SUCCESS) {
-                       chan->local_amp_id = local_amp_id;
-                       l2cap_send_create_chan_req(chan, remote_amp_id);
-               } else {
-                       /* Revert to BR/EDR connect */
-                       l2cap_send_conn_req(chan);
-               }
        }
 }
 
@@ -4501,14 +4620,15 @@ static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result)
        l2cap_ertm_send(chan);
 }
 
-void l2cap_physical_cfm(struct l2cap_chan *chan, int result, u8 local_amp_id,
-                       u8 remote_amp_id)
+/* Invoke with locked chan */
+void __l2cap_physical_cfm(struct l2cap_chan *chan, int result)
 {
+       u8 local_amp_id = chan->local_amp_id;
+       u8 remote_amp_id = chan->remote_amp_id;
+
        BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d",
               chan, result, local_amp_id, remote_amp_id);
 
-       l2cap_chan_lock(chan);
-
        if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) {
                l2cap_chan_unlock(chan);
                return;
@@ -4532,8 +4652,6 @@ void l2cap_physical_cfm(struct l2cap_chan *chan, int result, u8 local_amp_id,
                        break;
                }
        }
-
-       l2cap_chan_unlock(chan);
 }
 
 static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
@@ -5542,8 +5660,8 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,
                if (control->final) {
                        clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-                       if (!test_and_clear_bit(CONN_REJ_ACT,
-                                               &chan->conn_state)) {
+                       if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state) &&
+                           !__chan_is_moving(chan)) {
                                control->final = 0;
                                l2cap_retransmit_all(chan, control);
                        }
@@ -6189,9 +6307,9 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
                conn = l2cap_conn_add(hcon, status);
                if (conn)
                        l2cap_conn_ready(conn);
-       } else
+       } else {
                l2cap_conn_del(hcon, bt_to_errno(status));
-
+       }
 }
 
 int l2cap_disconn_ind(struct hci_conn *hcon)
@@ -6267,7 +6385,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        continue;
                }
 
-               if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
+               if (!__l2cap_no_conn_pending(chan)) {
                        l2cap_chan_unlock(chan);
                        continue;
                }