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; |