summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2004-11-17 13:21:33 +0100
committerMarcel Holtmann <linux-mh.adm@bkbits.net>2004-11-17 13:21:33 +0100
commitb01b5bbf311edcaf88b28e43db631851310012f6 (patch)
treef5f76b7c4be5fbc112add8e094e1adfa7a0bc962
parent4227e3a886a778c3074fcb837c5d4647a417a177 (diff)
[Bluetooth] Check for L2CAP reliability
The L2CAP sockets can now set LM_RELIABLE flag and get notification when a reliability problem with the ACL connection is detected. The Bluetooth qualification tests require this functionality. Signed-off-by: Maxim Krasnyansky <maxk@qualcomm.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--net/bluetooth/l2cap.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 222184e6e5d4..498572901276 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1100,6 +1100,22 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
read_unlock(&l->lock);
}
+/* Notify sockets that we cannot guaranty reliability anymore */
+static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
+{
+ struct l2cap_chan_list *l = &conn->chan_list;
+ struct sock *sk;
+
+ BT_DBG("conn %p", conn);
+
+ read_lock(&l->lock);
+ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
+ sk->sk_err = err;
+ }
+ read_unlock(&l->lock);
+}
+
static void l2cap_chan_ready(struct sock *sk)
{
struct sock *parent = bt_sk(sk)->parent;
@@ -2045,10 +2061,12 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
kfree_skb(conn->rx_skb);
conn->rx_skb = NULL;
conn->rx_len = 0;
+ l2cap_conn_unreliable(conn, ECOMM);
}
if (skb->len < 2) {
BT_ERR("Frame is too short (len %d)", skb->len);
+ l2cap_conn_unreliable(conn, ECOMM);
goto drop;
}
@@ -2066,6 +2084,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
if (skb->len > len) {
BT_ERR("Frame is too long (len %d, expected len %d)",
skb->len, len);
+ l2cap_conn_unreliable(conn, ECOMM);
goto drop;
}
@@ -2080,6 +2099,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
if (!conn->rx_len) {
BT_ERR("Unexpected continuation frame (len %d)", skb->len);
+ l2cap_conn_unreliable(conn, ECOMM);
goto drop;
}
@@ -2089,6 +2109,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
kfree_skb(conn->rx_skb);
conn->rx_skb = NULL;
conn->rx_len = 0;
+ l2cap_conn_unreliable(conn, ECOMM);
goto drop;
}