Bluetooth: Remove the send_lock spinlock from ERTM
[cascardo/linux.git] / net / bluetooth / l2cap.c
index 65c6a98..dc8601f 100644 (file)
@@ -456,6 +456,22 @@ static void l2cap_do_start(struct sock *sk)
        }
 }
 
+static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
+{
+       u32 local_feat_mask = l2cap_feat_mask;
+       if (enable_ertm)
+               local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
+
+       switch (mode) {
+       case L2CAP_MODE_ERTM:
+               return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
+       case L2CAP_MODE_STREAMING:
+               return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
+       default:
+               return 0x00;
+       }
+}
+
 static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err)
 {
        struct l2cap_disconn_req req;
@@ -484,10 +500,13 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int
 static void l2cap_conn_start(struct l2cap_conn *conn)
 {
        struct l2cap_chan_list *l = &conn->chan_list;
+       struct sock_del_list del, *tmp1, *tmp2;
        struct sock *sk;
 
        BT_DBG("conn %p", conn);
 
+       INIT_LIST_HEAD(&del.list);
+
        read_lock(&l->lock);
 
        for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
@@ -503,6 +522,19 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        if (l2cap_check_security(sk) &&
                                        __l2cap_no_conn_pending(sk)) {
                                struct l2cap_conn_req req;
+
+                               if (!l2cap_mode_supported(l2cap_pi(sk)->mode,
+                                               conn->feat_mask)
+                                               && l2cap_pi(sk)->conf_state &
+                                               L2CAP_CONF_STATE2_DEVICE) {
+                                       tmp1 = kzalloc(sizeof(struct srej_list),
+                                                       GFP_ATOMIC);
+                                       tmp1->sk = sk;
+                                       list_add_tail(&tmp1->list, &del.list);
+                                       bh_unlock_sock(sk);
+                                       continue;
+                               }
+
                                req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
                                req.psm  = l2cap_pi(sk)->psm;
 
@@ -542,6 +574,14 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
        }
 
        read_unlock(&l->lock);
+
+       list_for_each_entry_safe(tmp1, tmp2, &del.list, list) {
+               bh_lock_sock(tmp1->sk);
+               __l2cap_sock_close(tmp1->sk, ECONNRESET);
+               bh_unlock_sock(tmp1->sk);
+               list_del(&tmp1->list);
+               kfree(tmp1);
+       }
 }
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -831,6 +871,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 
                pi->imtu = l2cap_pi(parent)->imtu;
                pi->omtu = l2cap_pi(parent)->omtu;
+               pi->conf_state = l2cap_pi(parent)->conf_state;
                pi->mode = l2cap_pi(parent)->mode;
                pi->fcs  = l2cap_pi(parent)->fcs;
                pi->max_tx = l2cap_pi(parent)->max_tx;
@@ -841,10 +882,12 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
        } else {
                pi->imtu = L2CAP_DEFAULT_MTU;
                pi->omtu = 0;
-               if (enable_ertm && sk->sk_type == SOCK_STREAM)
+               if (enable_ertm && sk->sk_type == SOCK_STREAM) {
                        pi->mode = L2CAP_MODE_ERTM;
-               else
+                       pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+               } else {
                        pi->mode = L2CAP_MODE_BASIC;
+               }
                pi->max_tx = L2CAP_DEFAULT_MAX_TX;
                pi->fcs  = L2CAP_FCS_CRC16;
                pi->tx_win = L2CAP_DEFAULT_TX_WINDOW;
@@ -1519,16 +1562,11 @@ static int l2cap_retransmit_frames(struct sock *sk)
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        int ret;
 
-       spin_lock_bh(&pi->send_lock);
-
        if (!skb_queue_empty(TX_QUEUE(sk)))
                sk->sk_send_head = TX_QUEUE(sk)->next;
 
        pi->next_tx_seq = pi->expected_ack_seq;
        ret = l2cap_ertm_send(sk);
-
-       spin_unlock_bh(&pi->send_lock);
-
        return ret;
 }
 
@@ -1536,7 +1574,6 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi)
 {
        struct sock *sk = (struct sock *)pi;
        u16 control = 0;
-       int nframes;
 
        control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 
@@ -1547,11 +1584,7 @@ static void l2cap_send_ack(struct l2cap_pinfo *pi)
                return;
        }
 
-       spin_lock_bh(&pi->send_lock);
-       nframes = l2cap_ertm_send(sk);
-       spin_unlock_bh(&pi->send_lock);
-
-       if (nframes > 0)
+       if (l2cap_ertm_send(sk) > 0)
                return;
 
        control |= L2CAP_SUPER_RCV_READY;
@@ -1746,10 +1779,8 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz
                size += buflen;
        }
        skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk));
-       spin_lock_bh(&pi->send_lock);
        if (sk->sk_send_head == NULL)
                sk->sk_send_head = sar_queue.next;
-       spin_unlock_bh(&pi->send_lock);
 
        return size;
 }
@@ -1821,14 +1852,9 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                        }
                        __skb_queue_tail(TX_QUEUE(sk), skb);
 
-                       if (pi->mode == L2CAP_MODE_ERTM)
-                               spin_lock_bh(&pi->send_lock);
-
                        if (sk->sk_send_head == NULL)
                                sk->sk_send_head = skb;
 
-                       if (pi->mode == L2CAP_MODE_ERTM)
-                               spin_unlock_bh(&pi->send_lock);
                } else {
                /* Segment SDU into multiples PDUs */
                        err = l2cap_sar_segment_sdu(sk, msg, len);
@@ -1844,9 +1870,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                                err = len;
                                break;
                        }
-                       spin_lock_bh(&pi->send_lock);
                        err = l2cap_ertm_send(sk);
-                       spin_unlock_bh(&pi->send_lock);
                }
 
                if (err >= 0)
@@ -1925,6 +1949,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                l2cap_pi(sk)->mode = opts.mode;
                switch (l2cap_pi(sk)->mode) {
                case L2CAP_MODE_BASIC:
+                       l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE;
                        break;
                case L2CAP_MODE_ERTM:
                case L2CAP_MODE_STREAMING:
@@ -2420,27 +2445,10 @@ static inline void l2cap_ertm_init(struct sock *sk)
 
        __skb_queue_head_init(SREJ_QUEUE(sk));
        __skb_queue_head_init(BUSY_QUEUE(sk));
-       spin_lock_init(&l2cap_pi(sk)->send_lock);
 
        INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
 }
 
-static int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
-{
-       u32 local_feat_mask = l2cap_feat_mask;
-       if (enable_ertm)
-               local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
-
-       switch (mode) {
-       case L2CAP_MODE_ERTM:
-               return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
-       case L2CAP_MODE_STREAMING:
-               return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
-       default:
-               return 0x00;
-       }
-}
-
 static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
 {
        switch (mode) {
@@ -2469,10 +2477,10 @@ static int l2cap_build_conf_req(struct sock *sk, void *data)
        switch (pi->mode) {
        case L2CAP_MODE_STREAMING:
        case L2CAP_MODE_ERTM:
-               pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
-               if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask))
-                       l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
-               break;
+               if (pi->conf_state & L2CAP_CONF_STATE2_DEVICE)
+                       break;
+
+               /* fall through */
        default:
                pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask);
                break;
@@ -2483,6 +2491,14 @@ done:
        case L2CAP_MODE_BASIC:
                if (pi->imtu != L2CAP_DEFAULT_MTU)
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+
+               rfc.mode            = L2CAP_MODE_BASIC;
+               rfc.txwin_size      = 0;
+               rfc.max_transmit    = 0;
+               rfc.retrans_timeout = 0;
+               rfc.monitor_timeout = 0;
+               rfc.max_pdu_size    = 0;
+
                break;
 
        case L2CAP_MODE_ERTM:
@@ -2495,9 +2511,6 @@ done:
                if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
                        rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
-               l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
-
                if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
                        break;
 
@@ -2518,9 +2531,6 @@ done:
                if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
                        rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
-               l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
-
                if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
                        break;
 
@@ -2532,6 +2542,9 @@ done:
                break;
        }
 
+       l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+                                               (unsigned long) &rfc);
+
        /* FIXME: Need actual value of the flush timeout */
        //if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
        //   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
@@ -2602,12 +2615,15 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
        switch (pi->mode) {
        case L2CAP_MODE_STREAMING:
        case L2CAP_MODE_ERTM:
-               pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
-               if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask))
+               if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
+                       pi->mode = l2cap_select_mode(rfc.mode,
+                                       pi->conn->feat_mask);
+                       break;
+               }
+
+               if (pi->mode != rfc.mode)
                        return -ECONNREFUSED;
-               break;
-       default:
-               pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask);
+
                break;
        }
 
@@ -2730,7 +2746,6 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
                                                        rfc.mode != pi->mode)
                                return -ECONNREFUSED;
 
-                       pi->mode = rfc.mode;
                        pi->fcs = 0;
 
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
@@ -2739,6 +2754,11 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
                }
        }
 
+       if (pi->mode == L2CAP_MODE_BASIC && pi->mode != rfc.mode)
+               return -ECONNREFUSED;
+
+       pi->mode = rfc.mode;
+
        if (*result == L2CAP_CONF_SUCCESS) {
                switch (rfc.mode) {
                case L2CAP_MODE_ERTM:
@@ -3012,8 +3032,14 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (!sk)
                return -ENOENT;
 
-       if (sk->sk_state == BT_DISCONN)
+       if (sk->sk_state != BT_CONFIG) {
+               struct l2cap_cmd_rej rej;
+
+               rej.reason = cpu_to_le16(0x0002);
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
+                               sizeof(rej), &rej);
                goto unlock;
+       }
 
        /* Reject if config buffer is too small. */
        len = cmd_len - sizeof(*req);
@@ -3416,9 +3442,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
        if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY)
                l2cap_retransmit_frames(sk);
 
-       spin_lock_bh(&pi->send_lock);
        l2cap_ertm_send(sk);
-       spin_unlock_bh(&pi->send_lock);
 
        if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
                        pi->frames_sent == 0) {
@@ -4020,9 +4044,7 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)
                if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
                        l2cap_send_ack(pi);
                } else {
-                       spin_lock_bh(&pi->send_lock);
                        l2cap_ertm_send(sk);
-                       spin_unlock_bh(&pi->send_lock);
                }
        }
 }
@@ -4067,9 +4089,7 @@ static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control)
                pi->conn_state |= L2CAP_CONN_SEND_FBIT;
                l2cap_retransmit_one_frame(sk, tx_seq);
 
-               spin_lock_bh(&pi->send_lock);
                l2cap_ertm_send(sk);
-               spin_unlock_bh(&pi->send_lock);
 
                if (pi->conn_state & L2CAP_CONN_WAIT_F) {
                        pi->srej_save_reqseq = tx_seq;