diff options
author | Nick Pelly <npelly@google.com> | 2009-12-08 19:42:21 -0800 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2010-09-29 17:49:23 -0700 |
commit | 8401653065a6c0adbf7f54e94f7ee1a85467f01c (patch) | |
tree | 5bda24eb52ce117fe496fe12f86791c544943053 | |
parent | 197cf17c5c81851981f2f3fceead81299a901077 (diff) |
Bluetooth: Introduce L2CAP_LM_FLUSHABLE to allow flushing of ACL packets.
With Bluetooth 2.1 ACL packets can be flushable or non-flushable. This changes
makes the default ACL packet non-flushable, and allows selection of flushable
packets on a per-L2CAP socket basis with L2CAP_LM_FLUSHABLE.
Note the HCI Write Automatic Flush Timeout command also needs to be issued
to set the flush timeout to non-zero.
Need to featurize this change to Bluetooth 2.1 chipsets only before pushing
upstream.
Signed-off-by: Nick Pelly <npelly@google.com>
-rw-r--r-- | include/net/bluetooth/hci.h | 5 | ||||
-rw-r--r-- | include/net/bluetooth/l2cap.h | 2 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 6 | ||||
-rw-r--r-- | net/bluetooth/l2cap.c | 18 |
4 files changed, 25 insertions, 6 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 84ae84074973..2a833d9aa28a 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -150,11 +150,14 @@ enum { #define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5) /* ACL flags */ +#define ACL_START 0x00 #define ACL_CONT 0x01 -#define ACL_START 0x02 +#define ACL_START_FLUSHABLE 0x02 #define ACL_ACTIVE_BCAST 0x04 #define ACL_PICO_BCAST 0x08 +#define ACL_PB_MASK (ACL_CONT | ACL_START | ACL_START_FLUSHABLE) + /* Baseband links */ #define SCO_LINK 0x00 #define ACL_LINK 0x01 diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 6c241444f902..bcb78529c390 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -75,6 +75,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 @@ -327,6 +328,7 @@ struct l2cap_pinfo { __u8 sec_level; __u8 role_switch; __u8 force_reliable; + __u8 flushable; __u8 conf_req[64]; __u8 conf_len; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c52f091ee6de..a49aa2bf97f3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1367,7 +1367,7 @@ void 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 */ @@ -1384,12 +1384,14 @@ void 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); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index fadf26b4ed7c..8eed5d5abe87 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -360,7 +360,7 @@ static inline void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u1 if (!skb) return; - hci_send_acl(conn->hcon, skb, 0); + hci_send_acl(conn->hcon, skb, ACL_START); } static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) @@ -900,6 +900,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; @@ -915,6 +916,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 */ @@ -1433,10 +1435,16 @@ 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); + u16 flags; BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len); - hci_send_acl(pi->conn->hcon, skb, 0); + if (pi->flushable) + flags = ACL_START_FLUSHABLE; + else + flags = ACL_START; + + hci_send_acl(pi->conn->hcon, skb, flags); } static void l2cap_streaming_send(struct sock *sk) @@ -2016,6 +2024,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: @@ -2146,6 +2155,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; @@ -4645,7 +4657,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; |