|
@@ -3728,6 +3728,36 @@ done:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct sock *sk;
|
|
|
+
|
|
|
+ sk = l2cap_get_sock_by_scid(0, cid, conn->src);
|
|
|
+ if (!sk)
|
|
|
+ goto drop;
|
|
|
+
|
|
|
+ bh_lock_sock(sk);
|
|
|
+
|
|
|
+ BT_DBG("sk %p, len %d", sk, skb->len);
|
|
|
+
|
|
|
+ if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
|
|
|
+ goto drop;
|
|
|
+
|
|
|
+ if (l2cap_pi(sk)->imtu < skb->len)
|
|
|
+ goto drop;
|
|
|
+
|
|
|
+ if (!sock_queue_rcv_skb(sk, skb))
|
|
|
+ goto done;
|
|
|
+
|
|
|
+drop:
|
|
|
+ kfree_skb(skb);
|
|
|
+
|
|
|
+done:
|
|
|
+ if (sk)
|
|
|
+ bh_unlock_sock(sk);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
{
|
|
|
struct l2cap_hdr *lh = (void *) skb->data;
|
|
@@ -3757,6 +3787,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
|
|
|
l2cap_conless_channel(conn, psm, skb);
|
|
|
break;
|
|
|
|
|
|
+ case L2CAP_CID_LE_DATA:
|
|
|
+ l2cap_att_channel(conn, cid, skb);
|
|
|
+ break;
|
|
|
+
|
|
|
default:
|
|
|
l2cap_data_channel(conn, cid, skb);
|
|
|
break;
|