Skip to content
Permalink
Browse files
Bluetooth: Handle MSFT avdtp open event
On receiving MSFT avdtp open event, cache avdtp handle and
signal the task waiting on avdtp handle.

Signed-off-by: Kiran K <kiran.k@intel.com>
Reviewed-by: Chethan T N <chethan.tumkur.narayan@intel.com>
Reviewed-by: Srivatsa Ravishankar <ravishankar.srivatsa@intel.com>
  • Loading branch information
kirankrishnappa-intel authored and intel-lab-lkp committed Nov 15, 2021
1 parent 858ae46 commit 0a4eb6e6849d95c7565face4fc18ef652bacad11
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 4 deletions.
@@ -317,13 +317,15 @@ struct bt_sock {
struct list_head accept_q;
struct sock *parent;
unsigned long flags;
u16 avdtp_handle;
void (*skb_msg_name)(struct sk_buff *, void *, int *);
void (*skb_put_cmsg)(struct sk_buff *, struct msghdr *, struct sock *);
};

enum {
BT_SK_DEFER_SETUP,
BT_SK_SUSPEND,
BT_SK_AVDTP_PEND,
};

struct bt_sock_list {
@@ -346,6 +348,7 @@ __poll_t bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait);
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
int bt_sock_wait_ready(struct sock *sk, unsigned long flags);
int bt_sock_wait_for_avdtp_hndl(struct sock *sk, unsigned long timeo);

void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh);
void bt_accept_unlink(struct sock *sk);
@@ -347,6 +347,7 @@ enum {
#define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */
#define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */
#define HCI_LE_AUTOCONN_TIMEOUT msecs_to_jiffies(4000) /* 4 seconds */
#define MSFT_AVDTP_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */

/* HCI data types */
#define HCI_COMMAND_PKT 0x01
@@ -669,6 +669,8 @@ struct l2cap_ops {
unsigned long len, int nb);
int (*filter) (struct l2cap_chan * chan,
struct sk_buff *skb);
void (*avdtp_wakeup) (struct l2cap_chan *chan,
u8 status, u16 handle);
};

struct l2cap_conn {
@@ -1001,6 +1003,8 @@ void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);

struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn);
void l2cap_conn_put(struct l2cap_conn *conn);
void l2cap_avdtp_wakeup(struct l2cap_conn *conn, u16 dcid, u8 status,
u16 handle);

int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user);
void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user);
@@ -607,6 +607,42 @@ int bt_sock_wait_ready(struct sock *sk, unsigned long flags)
}
EXPORT_SYMBOL(bt_sock_wait_ready);

/* This function expects the sk lock to be held when called */
int bt_sock_wait_for_avdtp_hndl(struct sock *sk, unsigned long timeo)
{
DECLARE_WAITQUEUE(wait, current);
int err = 0;

BT_DBG("sk %p", sk);

add_wait_queue(sk_sleep(sk), &wait);
set_current_state(TASK_INTERRUPTIBLE);
while (test_bit(BT_SK_AVDTP_PEND, &bt_sk(sk)->flags)) {
if (!timeo) {
err = -EINPROGRESS;
break;
}

if (signal_pending(current)) {
err = sock_intr_errno(timeo);
break;
}

release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
set_current_state(TASK_INTERRUPTIBLE);

err = sock_error(sk);
if (err)
break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
return err;
}
EXPORT_SYMBOL(bt_sock_wait_for_avdtp_hndl);

#ifdef CONFIG_PROC_FS
static void *bt_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(seq->private->l->lock)
@@ -357,7 +357,7 @@ int hci_get_supported_codecs(struct hci_dev *hdev, u8 type, char __user *optval,
}

int hci_configure_msft_avdtp_open(struct hci_dev *hdev, struct l2cap_chan *chan,
sockptr_t optval, int optlen)
sockptr_t optval, int optlen, struct sock *sk)
{
struct msft_cp_avdtp_open *cmd = NULL;
struct hci_media_service_caps *caps;
@@ -392,7 +392,9 @@ int hci_configure_msft_avdtp_open(struct hci_dev *hdev, struct l2cap_chan *chan,

hci_send_cmd(hdev, HCI_MSFT_AVDTP_CMD, sizeof(*cmd) + optlen, cmd);

/* wait until we get avdtp handle or timeout */
set_bit(BT_SK_AVDTP_PEND, &bt_sk(sk)->flags);

err = bt_sock_wait_for_avdtp_hndl(sk, MSFT_AVDTP_TIMEOUT);

fail:
kfree(cmd);
@@ -10,4 +10,4 @@ void hci_codec_list_clear(struct list_head *codec_list);
int hci_get_supported_codecs(struct hci_dev *hdev, u8 type, char __user *optval,
int __user *optlen, int len);
int hci_configure_msft_avdtp_open(struct hci_dev *hdev, struct l2cap_chan *chan,
sockptr_t optval, int optlen);
sockptr_t optval, int optlen, struct sock *sk);
@@ -1450,6 +1450,7 @@ static void hci_cc_msft_avdtp_open(struct hci_dev *hdev, struct sk_buff *skb)
struct msft_rp_avdtp_open *rp;
struct msft_cp_avdtp_open *sent;
struct hci_conn *hconn;
struct l2cap_conn *conn;

if (skb->len < sizeof(*rp))
return;
@@ -1463,7 +1464,11 @@ static void hci_cc_msft_avdtp_open(struct hci_dev *hdev, struct sk_buff *skb)
if (!hconn)
return;

conn = hconn->l2cap_data;

/* wake up the task waiting on avdtp handle */
l2cap_avdtp_wakeup(conn, sent->dcid, rp->status,
rp->status ? 0 : __le16_to_cpu(rp->avdtp_handle));
}

static void hci_cc_msft_avdtp_cmd(struct hci_dev *hdev, struct sk_buff *skb)
@@ -8507,6 +8507,21 @@ int __init l2cap_init(void)
return 0;
}

void l2cap_avdtp_wakeup(struct l2cap_conn *conn, u16 cid, u8 status,
u16 handle)
{
struct l2cap_chan *chan;

chan = l2cap_get_chan_by_dcid(conn, cid);

if (!chan)
return;

chan->ops->avdtp_wakeup(chan, status, handle);

l2cap_chan_unlock(chan);
}

void l2cap_exit(void)
{
debugfs_remove(l2cap_debugfs);
@@ -1157,7 +1157,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

err = hci_configure_msft_avdtp_open(hdev, chan, optval, optlen);
err = hci_configure_msft_avdtp_open(hdev, chan, optval,
optlen, sk);
hci_dev_put(hdev);
break;

@@ -1748,6 +1749,19 @@ static int l2cap_sock_filter(struct l2cap_chan *chan, struct sk_buff *skb)
return 0;
}

static void l2cap_sock_avdtp_wakeup(struct l2cap_chan *chan, u8 status,
u16 handle)
{
struct sock *sk = chan->data;

if (test_bit(BT_SK_AVDTP_PEND, &bt_sk(sk)->flags)) {
bt_sk(sk)->avdtp_handle = handle;
sk->sk_err = -bt_to_errno(status);
clear_bit(BT_SK_AVDTP_PEND, &bt_sk(sk)->flags);
sk->sk_state_change(sk);
}
}

static const struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb,
@@ -1764,6 +1778,7 @@ static const struct l2cap_ops l2cap_chan_ops = {
.get_peer_pid = l2cap_sock_get_peer_pid_cb,
.alloc_skb = l2cap_sock_alloc_skb_cb,
.filter = l2cap_sock_filter,
.avdtp_wakeup = l2cap_sock_avdtp_wakeup,
};

static void l2cap_sock_destruct(struct sock *sk)

0 comments on commit 0a4eb6e

Please sign in to comment.