Bluetooth: Use non-flushable pb flag by default for ACL data on capable chipsets.
authorNick Pelly <npelly@google.com>
Wed, 9 Dec 2009 03:42:21 +0000 (19:42 -0800)
committerNick Pelly <npelly@google.com>
Tue, 9 Mar 2010 20:09:56 +0000 (12:09 -0800)
With Bluetooth 2.1 ACL packets can be flushable or non-flushable. This commit
makes ACL data packets non-flushable by default on compatible chipsets, and
adds the L2CAP_LM_FLUSHABLE socket option to explicitly request flushable ACL
data packets for a given L2CAP socket. This is useful for A2DP data which can
be safely discarded if it can not be delivered within a short time (while
other ACL data should not be discarded).

Note that making ACL data flushable has no effect unless the automatic flush
timeout for that ACL link is changed from its default of 0 (infinite).

Change-Id: Ie3d4befdeaefb8c979de7ae603ff5ec462b3483c
Signed-off-by: Nick Pelly <npelly@google.com>
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
net/bluetooth/hci_core.c
net/bluetooth/l2cap.c

index 9716e5a2024f876a1193dc67915d789982862419..bfd23aeedc46e5176c965d64924a381462b44e1a 100644 (file)
@@ -145,11 +145,14 @@ enum {
                        EDR_ESCO_MASK)
 
 /* ACL flags */
+#define ACL_START_NO_FLUSH     0x00
 #define ACL_CONT               0x01
 #define ACL_START              0x02
 #define ACL_ACTIVE_BCAST       0x04
 #define ACL_PICO_BCAST         0x08
 
+#define ACL_PB_MASK    (ACL_CONT | ACL_START)
+
 /* Baseband links */
 #define SCO_LINK       0x00
 #define ACL_LINK       0x01
@@ -188,6 +191,7 @@ enum {
 #define LMP_EDR_ESCO_3M        0x40
 #define LMP_EDR_3S_ESCO        0x80
 
+#define LMP_NO_FLUSH   0x01
 #define LMP_SIMPLE_PAIR        0x08
 
 /* Connection modes */
index cbcc5b102cdbbbb7ac109cb3759c90df5376e2cc..f5da4e6cfc2513e8912760f77c1fca1937fd8b63 100644 (file)
@@ -479,6 +479,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
 #define lmp_esco_capable(dev)      ((dev)->features[3] & LMP_ESCO)
 #define lmp_ssp_capable(dev)       ((dev)->features[6] & LMP_SIMPLE_PAIR)
+#define lmp_no_flush_capable(dev)  ((dev)->features[6] & LMP_NO_FLUSH)
 
 /* ----- HCI protocols ----- */
 struct hci_proto {
index 9516f4b4a3c235169404a1d589edfcb2eb378d46..23f37b487977dc00b8e188f14768e797ade566d8 100644 (file)
@@ -70,6 +70,7 @@ struct l2cap_conninfo {
 #define L2CAP_LM_TRUSTED       0x0008
 #define L2CAP_LM_RELIABLE      0x0010
 #define L2CAP_LM_SECURE                0x0020
+#define L2CAP_LM_FLUSHABLE     0x0040
 
 /* L2CAP command codes */
 #define L2CAP_COMMAND_REJ      0x01
@@ -316,6 +317,7 @@ struct l2cap_pinfo {
        __u8            sec_level;
        __u8            role_switch;
        __u8            force_reliable;
+       __u8            flushable;
 
        __u8            conf_req[64];
        __u8            conf_len;
index e1da8f68759c3a989fc8cd8ddde64949c204f5a1..84a9d75b0c61ede0e98150490abecee369f3fb0f 100644 (file)
@@ -1239,7 +1239,7 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 
        skb->dev = (void *) hdev;
        bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-       hci_add_acl_hdr(skb, conn->handle, flags | ACL_START);
+       hci_add_acl_hdr(skb, conn->handle, flags);
 
        if (!(list = skb_shinfo(skb)->frag_list)) {
                /* Non fragmented */
@@ -1256,12 +1256,14 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
                spin_lock_bh(&conn->data_q.lock);
 
                __skb_queue_tail(&conn->data_q, skb);
+               flags &= ~ACL_PB_MASK;
+               flags |= ACL_CONT;
                do {
                        skb = list; list = list->next;
 
                        skb->dev = (void *) hdev;
                        bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-                       hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
+                       hci_add_acl_hdr(skb, conn->handle, flags);
 
                        BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
 
index 6e3b59690d0e663b833ac3d683d71d92a6086e1b..4529e99b2940dfa2b12997e9a19a6d1f23bc58eb 100644 (file)
@@ -325,13 +325,19 @@ static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
 static inline int 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 -ENOMEM;
 
-       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;
+
+       return hci_send_acl(conn->hcon, skb, flags);
 }
 
 static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
@@ -770,6 +776,7 @@ 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;
        } else {
                pi->imtu = L2CAP_DEFAULT_MTU;
                pi->omtu = 0;
@@ -778,6 +785,7 @@ 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;
        }
 
        /* Default config options */
@@ -1258,11 +1266,18 @@ static void l2cap_drop_acked_frames(struct sock *sk)
 static inline int l2cap_do_send(struct sock *sk, struct sk_buff *skb)
 {
        struct l2cap_pinfo *pi = l2cap_pi(sk);
+       struct hci_conn *hcon = pi->conn->hcon;
        int err;
+       u16 flags;
 
        BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len);
 
-       err = 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;
+
+       err = hci_send_acl(hcon, skb, flags);
        if (err < 0)
                kfree_skb(skb);
 
@@ -1747,6 +1762,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:
@@ -1874,6 +1890,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;
@@ -3801,7 +3820,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;
                int len;