diff options
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 70 |
1 files changed, 65 insertions, 5 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 675614e38e1..7e462e2609a 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -373,13 +373,21 @@ static inline u8 l2cap_get_ident(struct l2cap_conn *conn) static inline void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data) { struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); + u8 flags; BT_DBG("code 0x%2.2x", code); if (!skb) return; - hci_send_acl(conn->hcon, skb, 0); + if (lmp_no_flush_capable(conn->hcon->hdev)) + flags = ACL_START_NO_FLUSH; + else + flags = ACL_START; + + bt_cb(skb)->force_active = 1; + + hci_send_acl(conn->hcon, skb, flags); } static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) @@ -425,6 +433,8 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) put_unaligned_le16(fcs, skb_put(skb, 2)); } + bt_cb(skb)->force_active = l2cap_pi(sk)->force_active; + hci_send_acl(pi->conn->hcon, skb, 0); } @@ -583,7 +593,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); - parent->sk_data_ready(parent, 0); + if (parent) + parent->sk_data_ready(parent, 0); } else { sk->sk_state = BT_CONFIG; @@ -912,6 +923,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->sec_level = l2cap_pi(parent)->sec_level; pi->role_switch = l2cap_pi(parent)->role_switch; pi->force_reliable = l2cap_pi(parent)->force_reliable; + pi->flushable = l2cap_pi(parent)->flushable; + pi->force_active = l2cap_pi(parent)->force_active; } else { pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; @@ -927,6 +940,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->sec_level = BT_SECURITY_LOW; pi->role_switch = 0; pi->force_reliable = 0; + pi->flushable = 0; + pi->force_active = 1; } /* Default config options */ @@ -1082,7 +1097,7 @@ static int l2cap_do_connect(struct sock *sk) auth_type = l2cap_get_auth_type(sk); - hcon = hci_connect(hdev, ACL_LINK, dst, + hcon = hci_connect(hdev, ACL_LINK, 0, dst, l2cap_pi(sk)->sec_level, auth_type); if (!hcon) goto done; @@ -1431,10 +1446,18 @@ static void l2cap_drop_acked_frames(struct sock *sk) static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb) { struct l2cap_pinfo *pi = l2cap_pi(sk); + struct hci_conn *hcon = pi->conn->hcon; + u16 flags; BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len); - hci_send_acl(pi->conn->hcon, skb, 0); + if (lmp_no_flush_capable(hcon->hdev) && !l2cap_pi(sk)->flushable) + flags = ACL_START_NO_FLUSH; + else + flags = ACL_START; + + bt_cb(skb)->force_active = pi->force_active; + hci_send_acl(hcon, skb, flags); } static void l2cap_streaming_send(struct sock *sk) @@ -2012,6 +2035,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER); l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE); + l2cap_pi(sk)->flushable = (opt & L2CAP_LM_FLUSHABLE); break; default: @@ -2027,6 +2051,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch { struct sock *sk = sock->sk; struct bt_security sec; + struct bt_power pwr; int len, err = 0; u32 opt; @@ -2079,6 +2104,23 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch bt_sk(sk)->defer_setup = opt; break; + case BT_POWER: + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM + && sk->sk_type != SOCK_RAW) { + err = -EINVAL; + break; + } + + pwr.force_active = 1; + + len = min_t(unsigned int, sizeof(pwr), optlen); + if (copy_from_user((char *) &pwr, optval, len)) { + err = -EFAULT; + break; + } + l2cap_pi(sk)->force_active = pwr.force_active; + break; + default: err = -ENOPROTOOPT; break; @@ -2142,6 +2184,9 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us if (l2cap_pi(sk)->force_reliable) opt |= L2CAP_LM_RELIABLE; + if (l2cap_pi(sk)->flushable) + opt |= L2CAP_LM_FLUSHABLE; + if (put_user(opt, (u32 __user *) optval)) err = -EFAULT; break; @@ -2176,6 +2221,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch { struct sock *sk = sock->sk; struct bt_security sec; + struct bt_power pwr; int len, err = 0; BT_DBG("sk %p", sk); @@ -2218,6 +2264,20 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; + case BT_POWER: + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM + && sk->sk_type != SOCK_RAW) { + err = -EINVAL; + break; + } + + pwr.force_active = l2cap_pi(sk)->force_active; + + len = min_t(unsigned int, len, sizeof(pwr)); + if (copy_to_user(optval, (char *) &pwr, len)) + err = -EFAULT; + + break; default: err = -ENOPROTOOPT; break; @@ -4678,7 +4738,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags); - if (flags & ACL_START) { + if (!(flags & ACL_CONT)) { struct l2cap_hdr *hdr; struct sock *sk; u16 cid; |