| Index: chromeos/compat-wireless/net/bluetooth/l2cap.c
|
| diff --git a/chromeos/compat-wireless/net/bluetooth/l2cap.c b/chromeos/compat-wireless/net/bluetooth/l2cap.c
|
| index f52cc610f19c7724a428f66117b3984fb4db721f..11acab6687acef479b6c336c7bb3a3354320023b 100644
|
| --- a/chromeos/compat-wireless/net/bluetooth/l2cap.c
|
| +++ b/chromeos/compat-wireless/net/bluetooth/l2cap.c
|
| @@ -1449,33 +1449,23 @@ static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
|
|
|
| static void l2cap_streaming_send(struct sock *sk)
|
| {
|
| - struct sk_buff *skb, *tx_skb;
|
| + struct sk_buff *skb;
|
| struct l2cap_pinfo *pi = l2cap_pi(sk);
|
| u16 control, fcs;
|
|
|
| - while ((skb = sk->sk_send_head)) {
|
| - tx_skb = skb_clone(skb, GFP_ATOMIC);
|
| -
|
| - control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
|
| + while ((skb = skb_dequeue(TX_QUEUE(sk)))) {
|
| + control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
|
| control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
|
| - put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
|
| + put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
|
|
|
| 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);
|
| + fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
|
| + put_unaligned_le16(fcs, skb->data + skb->len - 2);
|
| }
|
|
|
| - l2cap_do_send(sk, tx_skb);
|
| + l2cap_do_send(sk, skb);
|
|
|
| pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
|
| -
|
| - if (skb_queue_is_last(TX_QUEUE(sk), skb))
|
| - sk->sk_send_head = NULL;
|
| - else
|
| - sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
|
| -
|
| - skb = skb_dequeue(TX_QUEUE(sk));
|
| - kfree_skb(skb);
|
| }
|
| }
|
|
|
| @@ -1968,6 +1958,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
|
|
|
| switch (optname) {
|
| case L2CAP_OPTIONS:
|
| + if (sk->sk_state == BT_CONNECTED) {
|
| + err = -EINVAL;
|
| + break;
|
| + }
|
| +
|
| opts.imtu = l2cap_pi(sk)->imtu;
|
| opts.omtu = l2cap_pi(sk)->omtu;
|
| opts.flush_to = l2cap_pi(sk)->flush_to;
|
| @@ -2783,10 +2778,10 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
|
| case L2CAP_CONF_MTU:
|
| if (val < L2CAP_DEFAULT_MIN_MTU) {
|
| *result = L2CAP_CONF_UNACCEPT;
|
| - pi->omtu = L2CAP_DEFAULT_MIN_MTU;
|
| + pi->imtu = L2CAP_DEFAULT_MIN_MTU;
|
| } else
|
| - pi->omtu = val;
|
| - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
|
| + pi->imtu = val;
|
| + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
|
| break;
|
|
|
| case L2CAP_CONF_FLUSH_TO:
|
| @@ -3083,6 +3078,17 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
|
| return 0;
|
| }
|
|
|
| +static inline void set_default_fcs(struct l2cap_pinfo *pi)
|
| +{
|
| + /* FCS is enabled only in ERTM or streaming mode, if one or both
|
| + * sides request it.
|
| + */
|
| + if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING)
|
| + pi->fcs = L2CAP_FCS_NONE;
|
| + else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV))
|
| + pi->fcs = L2CAP_FCS_CRC16;
|
| +}
|
| +
|
| static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
|
| {
|
| struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
|
| @@ -3100,14 +3106,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
|
| if (!sk)
|
| return -ENOENT;
|
|
|
| - 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);
|
| + if (sk->sk_state == BT_DISCONN)
|
| goto unlock;
|
| - }
|
|
|
| /* Reject if config buffer is too small. */
|
| len = cmd_len - sizeof(*req);
|
| @@ -3147,9 +3147,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
|
| goto unlock;
|
|
|
| if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
|
| - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) ||
|
| - l2cap_pi(sk)->fcs != L2CAP_FCS_NONE)
|
| - l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16;
|
| + set_default_fcs(l2cap_pi(sk));
|
|
|
| sk->sk_state = BT_CONNECTED;
|
|
|
| @@ -3237,9 +3235,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
|
| l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
|
|
|
| if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
|
| - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_NO_FCS_RECV) ||
|
| - l2cap_pi(sk)->fcs != L2CAP_FCS_NONE)
|
| - l2cap_pi(sk)->fcs = L2CAP_FCS_CRC16;
|
| + set_default_fcs(l2cap_pi(sk));
|
|
|
| sk->sk_state = BT_CONNECTED;
|
| l2cap_pi(sk)->next_tx_seq = 0;
|
|
|