Bluetooth: Support case with F bit set under WAIT_F state.
[cascardo/linux.git] / net / bluetooth / l2cap.c
index 7794a2e..36cd4e4 100644 (file)
@@ -1002,7 +1002,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
 
        BT_DBG("sk %p", sk);
 
-       if (!addr || addr->sa_family != AF_BLUETOOTH)
+       if (!addr || alen < sizeof(addr->sa_family) ||
+           addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
        memset(&la, 0, sizeof(la));
@@ -1146,7 +1147,7 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl
        BT_DBG("sk %p timeo %ld", sk, timeo);
 
        /* Wait for an incoming connection. (wake-one). */
-       add_wait_queue_exclusive(sk->sk_sleep, &wait);
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
        while (!(nsk = bt_accept_dequeue(sk, newsock))) {
                set_current_state(TASK_INTERRUPTIBLE);
                if (!timeo) {
@@ -1169,7 +1170,7 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl
                }
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
 
        if (err)
                goto done;
@@ -1290,7 +1291,7 @@ static int l2cap_streaming_send(struct sock *sk)
                control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
                put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
-               if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) {
+               if (pi->fcs == L2CAP_FCS_CRC16) {
                        fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
                        put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
                }
@@ -1343,7 +1344,7 @@ static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq)
                                | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
                put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
-               if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) {
+               if (pi->fcs == L2CAP_FCS_CRC16) {
                        fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
                        put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
                }
@@ -1382,12 +1383,16 @@ static int l2cap_ertm_send(struct sock *sk)
                bt_cb(skb)->retries++;
 
                control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+               if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+                       control |= L2CAP_CTRL_FINAL;
+                       pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+               }
                control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
                                | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
                put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
 
-               if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) {
+               if (pi->fcs == L2CAP_FCS_CRC16) {
                        fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
                        put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
                }
@@ -1403,6 +1408,7 @@ static int l2cap_ertm_send(struct sock *sk)
                pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
 
                pi->unacked_frames++;
+               pi->frames_sent++;
 
                if (skb_queue_is_last(TX_QUEUE(sk), skb))
                        sk->sk_send_head = NULL;
@@ -1610,11 +1616,6 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        if (msg->msg_flags & MSG_OOB)
                return -EOPNOTSUPP;
 
-       /* Check outgoing MTU */
-       if (sk->sk_type == SOCK_SEQPACKET && pi->mode == L2CAP_MODE_BASIC &&
-           len > pi->omtu)
-               return -EINVAL;
-
        lock_sock(sk);
 
        if (sk->sk_state != BT_CONNECTED) {
@@ -1625,12 +1626,21 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        /* Connectionless channel */
        if (sk->sk_type == SOCK_DGRAM) {
                skb = l2cap_create_connless_pdu(sk, msg, len);
-               err = l2cap_do_send(sk, skb);
+               if (IS_ERR(skb))
+                       err = PTR_ERR(skb);
+               else
+                       err = l2cap_do_send(sk, skb);
                goto done;
        }
 
        switch (pi->mode) {
        case L2CAP_MODE_BASIC:
+               /* Check outgoing MTU */
+               if (len > pi->omtu) {
+                       err = -EINVAL;
+                       goto done;
+               }
+
                /* Create a basic PDU */
                skb = l2cap_create_basic_pdu(sk, msg, len);
                if (IS_ERR(skb)) {
@@ -2186,6 +2196,7 @@ static inline void l2cap_ertm_init(struct sock *sk)
        l2cap_pi(sk)->unacked_frames = 0;
        l2cap_pi(sk)->buffer_seq = 0;
        l2cap_pi(sk)->num_to_ack = 0;
+       l2cap_pi(sk)->frames_sent = 0;
 
        setup_timer(&l2cap_pi(sk)->retrans_timer,
                        l2cap_retrans_timeout, (unsigned long) sk);
@@ -2262,6 +2273,8 @@ done:
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
                rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
+               if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
+                       rfc.max_pdu_size = pi->conn->mtu - 10;
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
@@ -2283,6 +2296,8 @@ done:
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
                rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
+               if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
+                       rfc.max_pdu_size = pi->conn->mtu - 10;
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
@@ -3139,6 +3154,38 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi,  struct sk_buff *skb)
        return 0;
 }
 
+static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
+{
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       u16 control = 0;
+
+       pi->frames_sent = 0;
+       pi->conn_state |= L2CAP_CONN_SEND_FBIT;
+
+       control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+
+       if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+               control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL;
+               l2cap_send_sframe(pi, control);
+               pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+       }
+
+       if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0)
+               __mod_retrans_timer();
+
+       l2cap_ertm_send(sk);
+
+       if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
+                       pi->frames_sent == 0) {
+               control |= L2CAP_SUPER_RCV_READY;
+               if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+                       control |= L2CAP_CTRL_FINAL;
+                       pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+               }
+               l2cap_send_sframe(pi, control);
+       }
+}
+
 static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
 {
        struct sk_buff *next_skb;
@@ -3317,6 +3364,13 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
 
        BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
 
+       if (L2CAP_CTRL_FINAL & rx_control) {
+               del_timer(&pi->monitor_timer);
+               if (pi->unacked_frames > 0)
+                       __mod_retrans_timer();
+               pi->conn_state &= ~L2CAP_CONN_WAIT_F;
+       }
+
        pi->expected_ack_seq = req_seq;
        l2cap_drop_acked_frames(sk);
 
@@ -3406,13 +3460,17 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
 
        BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
 
+       if (L2CAP_CTRL_FINAL & rx_control) {
+               del_timer(&pi->monitor_timer);
+               if (pi->unacked_frames > 0)
+                       __mod_retrans_timer();
+               pi->conn_state &= ~L2CAP_CONN_WAIT_F;
+       }
+
        switch (rx_control & L2CAP_CTRL_SUPERVISE) {
        case L2CAP_SUPER_RCV_READY:
                if (rx_control & L2CAP_CTRL_POLL) {
-                       u16 control = L2CAP_CTRL_FINAL;
-                       control |= L2CAP_SUPER_RCV_READY |
-                               (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT);
-                       l2cap_send_sframe(l2cap_pi(sk), control);
+                       l2cap_send_i_or_rr_or_rnr(sk);
                        pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 
                } else if (rx_control & L2CAP_CTRL_FINAL) {
@@ -3428,14 +3486,6 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
                                l2cap_ertm_send(sk);
                        }
 
-                       if (!(pi->conn_state & L2CAP_CONN_WAIT_F))
-                               break;
-
-                       pi->conn_state &= ~L2CAP_CONN_WAIT_F;
-                       del_timer(&pi->monitor_timer);
-
-                       if (pi->unacked_frames > 0)
-                               __mod_retrans_timer();
                } else {
                        pi->expected_ack_seq = tx_seq;
                        l2cap_drop_acked_frames(sk);
@@ -3509,14 +3559,15 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
                pi->expected_ack_seq = tx_seq;
                l2cap_drop_acked_frames(sk);
 
-               del_timer(&l2cap_pi(sk)->retrans_timer);
+               del_timer(&pi->retrans_timer);
                if (rx_control & L2CAP_CTRL_POLL) {
                        u16 control = L2CAP_CTRL_FINAL;
-                       l2cap_send_rr_or_rnr(l2cap_pi(sk), control);
+                       l2cap_send_rr_or_rnr(pi, control);
                }
                break;
        }
 
+       kfree_skb(skb);
        return 0;
 }
 
@@ -3605,14 +3656,14 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                if (pi->expected_tx_seq == tx_seq)
                        pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
                else
-                       pi->expected_tx_seq = tx_seq + 1;
+                       pi->expected_tx_seq = (tx_seq + 1) % 64;
 
                l2cap_sar_reassembly_sdu(sk, skb, control);
 
                goto done;
 
        default:
-               BT_DBG("sk %p: bad mode 0x%2.2x", sk, l2cap_pi(sk)->mode);
+               BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode);
                break;
        }