Bluetooth: Track both local and remote L2CAP fixed channel mask
authorJohan Hedberg <johan.hedberg@intel.com>
Tue, 2 Dec 2014 08:09:26 +0000 (10:09 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 2 Dec 2014 08:26:50 +0000 (09:26 +0100)
To pave the way for future fixed channels to be added easily we should
track both the local and remote mask on a per-L2CAP connection (struct
l2cap_conn) basis. So far the code has used a global variable in a racy
way which anyway needs fixing.

This patch renames the existing conn->fixed_chan_mask that tracked
the remote mask to conn->remote_fixed_chan and adds a new variable
conn->local_fixed_chan to track the local mask. Since the HS support
info is now available in the local mask we can remove the
conn->hs_enabled variable.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/l2cap.h
net/bluetooth/l2cap_core.c

index 061e648..d71dc35 100644 (file)
@@ -619,8 +619,8 @@ struct l2cap_conn {
        unsigned int            mtu;
 
        __u32                   feat_mask;
-       __u8                    fixed_chan_mask;
-       bool                    hs_enabled;
+       __u8                    remote_fixed_chan;
+       __u8                    local_fixed_chan;
 
        __u8                    info_state;
        __u8                    info_ident;
index c2d1489..43349ed 100644 (file)
@@ -46,7 +46,6 @@
 bool disable_ertm;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
-static u8 l2cap_fixed_chan[8] = { L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS, };
 
 static LIST_HEAD(chan_list);
 static DEFINE_RWLOCK(chan_list_lock);
@@ -1120,10 +1119,10 @@ static bool __amp_capable(struct l2cap_chan *chan)
        struct hci_dev *hdev;
        bool amp_available = false;
 
-       if (!conn->hs_enabled)
+       if (!(conn->local_fixed_chan & L2CAP_FC_A2MP))
                return false;
 
-       if (!(conn->fixed_chan_mask & L2CAP_FC_A2MP))
+       if (!(conn->remote_fixed_chan & L2CAP_FC_A2MP))
                return false;
 
        read_lock(&hci_dev_list_lock);
@@ -3096,12 +3095,14 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
 
 static inline bool __l2cap_ews_supported(struct l2cap_conn *conn)
 {
-       return conn->hs_enabled && conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
+       return ((conn->local_fixed_chan & L2CAP_FC_A2MP) &&
+               (conn->feat_mask & L2CAP_FEAT_EXT_WINDOW));
 }
 
 static inline bool __l2cap_efs_supported(struct l2cap_conn *conn)
 {
-       return conn->hs_enabled && conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
+       return ((conn->local_fixed_chan & L2CAP_FC_A2MP) &&
+               (conn->feat_mask & L2CAP_FEAT_EXT_FLOW));
 }
 
 static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan,
@@ -3330,7 +3331,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
                        break;
 
                case L2CAP_CONF_EWS:
-                       if (!chan->conn->hs_enabled)
+                       if (!(chan->conn->local_fixed_chan & L2CAP_FC_A2MP))
                                return -ECONNREFUSED;
 
                        set_bit(FLAG_EXT_CTRL, &chan->flags);
@@ -4334,7 +4335,7 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
                if (!disable_ertm)
                        feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
                                | L2CAP_FEAT_FCS;
-               if (conn->hs_enabled)
+               if (conn->local_fixed_chan & L2CAP_FC_A2MP)
                        feat_mask |= L2CAP_FEAT_EXT_FLOW
                                | L2CAP_FEAT_EXT_WINDOW;
 
@@ -4345,14 +4346,10 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
                u8 buf[12];
                struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
 
-               if (conn->hs_enabled)
-                       l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
-               else
-                       l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
-
                rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
                rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
-               memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
+               rsp->data[0] = conn->local_fixed_chan;
+               memset(rsp->data + 1, 0, 7);
                l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf),
                               buf);
        } else {
@@ -4418,7 +4415,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
                break;
 
        case L2CAP_IT_FIXED_CHAN:
-               conn->fixed_chan_mask = rsp->data[0];
+               conn->remote_fixed_chan = rsp->data[0];
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
                conn->info_ident = 0;
 
@@ -4442,7 +4439,7 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,
        if (cmd_len != sizeof(*req))
                return -EPROTO;
 
-       if (!conn->hs_enabled)
+       if (!(conn->local_fixed_chan & L2CAP_FC_A2MP))
                return -EINVAL;
 
        psm = le16_to_cpu(req->psm);
@@ -4872,7 +4869,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
 
        BT_DBG("icid 0x%4.4x, dest_amp_id %d", icid, req->dest_amp_id);
 
-       if (!conn->hs_enabled)
+       if (!(conn->local_fixed_chan & L2CAP_FC_A2MP))
                return -EINVAL;
 
        chan = l2cap_get_chan_by_dcid(conn, icid);
@@ -6964,9 +6961,11 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
 
        conn->feat_mask = 0;
 
-       if (hcon->type == ACL_LINK)
-               conn->hs_enabled = test_bit(HCI_HS_ENABLED,
-                                           &hcon->hdev->dev_flags);
+       conn->local_fixed_chan = L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS;
+
+       if (hcon->type == ACL_LINK &&
+           test_bit(HCI_HS_ENABLED, &hcon->hdev->dev_flags))
+               conn->local_fixed_chan |= L2CAP_FC_A2MP;
 
        mutex_init(&conn->ident_lock);
        mutex_init(&conn->chan_lock);