From: Arnaud Mouiche <arnaud.mouiche@invoxia.com>
To: "Frédéric Dalleau" <frederic.dalleau@linux.intel.com>
Cc: linux-bluetooth@vger.kernel.org
Subject: Re: [RFC] Bluetooth: Add BT_DEFER_SETUP option to sco socket
Date: Wed, 14 Nov 2012 11:09:21 +0100 [thread overview]
Message-ID: <50A36DD1.1080507@invoxia.com> (raw)
In-Reply-To: <1352830825-13987-2-git-send-email-frederic.dalleau@linux.intel.com>
Hello,
First thank you for this RFC. Defer (or something similar) is a must
have for mSBC vs CVSD connection accept from multiple device management,
at least for HFP case.
some comments / ideas:
- can't we take the opportunity to configure the whole set of eSCO
parameters (bandwith / latency / retransmission effort) instead of only
getting the possibility to change the voice settings
- can we introduce a better way to change the voice settings, instead of
modifying the adapter config (hdev->voice_setting)
- any possibility to reject the eSCO creating (for 'connection rejected
due to limited resources' reason)
I will try to find some time to try your patch.
regards,
arnaud
On 11/13/2012 07:20 PM, Frédéric Dalleau wrote:
> In order to authenticate and later configure an incoming SCO connection, the
> BT_DEFER_SETUP option is added.
> When an connection is requested, the listening socket is unblocked but the
> effective connection setup happens only on first recv.
> Any send between accept and recv fails with -ENOTCONN.
> ---
> include/net/bluetooth/hci_core.h | 15 +++++++
> net/bluetooth/hci_event.c | 47 +++++++++++++++++++-
> net/bluetooth/sco.c | 88 ++++++++++++++++++++++++++++++++++++--
> 3 files changed, 145 insertions(+), 5 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index ef5b85d..2ee0ecb 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -377,6 +377,7 @@ extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
> u16 flags);
>
> extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
> +extern int sco_defer(struct hci_dev *hdev, bdaddr_t *bdaddr);
> extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status);
> extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
> extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
> @@ -577,6 +578,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
> int hci_conn_del(struct hci_conn *conn);
> void hci_conn_hash_flush(struct hci_dev *hdev);
> void hci_conn_check_pending(struct hci_dev *hdev);
> +void hci_conn_accept(struct hci_conn *conn, int mask);
>
> struct hci_chan *hci_chan_create(struct hci_conn *conn);
> void hci_chan_del(struct hci_chan *chan);
> @@ -796,6 +798,19 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
> }
> }
>
> +static inline int hci_proto_defered(struct hci_dev *hdev, bdaddr_t *bdaddr,
> + __u8 type)
> +{
> + switch (type) {
> + case SCO_LINK:
> + case ESCO_LINK:
> + return sco_defer(hdev, bdaddr);
> +
> + default:
> + return 0;
> + }
> +}
> +
> static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
> {
> switch (conn->type) {
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 9f5c5f2..167eca0 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -2047,15 +2047,54 @@ unlock:
> hci_conn_check_pending(hdev);
> }
>
> +void hci_conn_accept(struct hci_conn *conn, int mask)
> +{
> + struct hci_dev *hdev = conn->hdev;
> +
> + BT_DBG("conn %p", conn);
> +
> + if (!lmp_esco_capable(hdev)) {
> + struct hci_cp_accept_conn_req cp;
> +
> + conn->state = BT_CONNECT;
> + bacpy(&cp.bdaddr, &conn->dst);
> +
> + if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
> + cp.role = 0x00; /* Become master */
> + else
> + cp.role = 0x01; /* Remain slave */
> +
> + hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp),
> + &cp);
> + } else /* lmp_esco_capable(hdev)) */ {
> + struct hci_cp_accept_sync_conn_req cp;
> +
> + conn->state = BT_CONNECT;
> + bacpy(&cp.bdaddr, &conn->dst);
> + cp.pkt_type = cpu_to_le16(conn->pkt_type);
> +
> + cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
> + cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
> + cp.max_latency = __constant_cpu_to_le16(0xffff);
> + cp.content_format = cpu_to_le16(hdev->voice_setting);
> + cp.retrans_effort = 0xff;
> +
> + hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
> + sizeof(cp), &cp);
> + }
> +}
> +
> static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
> {
> struct hci_ev_conn_request *ev = (void *) skb->data;
> int mask = hdev->link_mode;
> + int defered;
>
> BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr,
> ev->link_type);
>
> mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
> + defered = hci_proto_defered(hdev, &ev->bdaddr, ev->link_type);
>
> if ((mask & HCI_LM_ACCEPT) &&
> !hci_blacklist_lookup(hdev, &ev->bdaddr)) {
> @@ -2085,7 +2124,8 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
>
> hci_dev_unlock(hdev);
>
> - if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) {
> + if (ev->link_type == ACL_LINK ||
> + (!defered && !lmp_esco_capable(hdev))) {
> struct hci_cp_accept_conn_req cp;
>
> bacpy(&cp.bdaddr, &ev->bdaddr);
> @@ -2097,7 +2137,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
>
> hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp),
> &cp);
> - } else {
> + } else if (!defered) {
> struct hci_cp_accept_sync_conn_req cp;
>
> bacpy(&cp.bdaddr, &ev->bdaddr);
> @@ -2111,6 +2151,9 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
>
> hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
> sizeof(cp), &cp);
> + } else {
> + hci_proto_connect_cfm(conn, 0);
> + hci_conn_put(conn);
> }
> } else {
> /* Connection rejected */
> diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
> index 450cdcd..416801a 100644
> --- a/net/bluetooth/sco.c
> +++ b/net/bluetooth/sco.c
> @@ -662,16 +662,57 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
> return err;
> }
>
> +static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
> + struct msghdr *msg, size_t len, int flags)
> +{
> + struct sock *sk = sock->sk;
> + struct sco_pinfo *pi = sco_pi(sk);
> +
> + lock_sock(sk);
> +
> + if (sk->sk_state == BT_CONNECT &&
> + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
> + hci_conn_accept(pi->conn->hcon, 0);
> + sk->sk_state = BT_CONNECT2;
> +
> + release_sock(sk);
> + return 0;
> + }
> +
> + release_sock(sk);
> +
> + return bt_sock_recvmsg(iocb, sock, msg, len, flags);
> +}
> +
> static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
> {
> struct sock *sk = sock->sk;
> int err = 0;
> + u32 opt;
>
> BT_DBG("sk %p", sk);
>
> lock_sock(sk);
>
> switch (optname) {
> +
> + case BT_DEFER_SETUP:
> + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
> + err = -EINVAL;
> + break;
> + }
> +
> + if (get_user(opt, (u32 __user *) optval)) {
> + err = -EFAULT;
> + break;
> + }
> +
> + if (opt)
> + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
> + else
> + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
> + break;
> +
> default:
> err = -ENOPROTOOPT;
> break;
> @@ -753,6 +794,19 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
> lock_sock(sk);
>
> switch (optname) {
> +
> + case BT_DEFER_SETUP:
> + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
> + err = -EINVAL;
> + break;
> + }
> +
> + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
> + (u32 __user *) optval))
> + err = -EFAULT;
> +
> + break;
> +
> default:
> err = -ENOPROTOOPT;
> break;
> @@ -874,7 +928,10 @@ static void sco_conn_ready(struct sco_conn *conn)
> hci_conn_hold(conn->hcon);
> __sco_chan_add(conn, sk, parent);
>
> - sk->sk_state = BT_CONNECTED;
> + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
> + sk->sk_state = BT_CONNECT;
> + else
> + sk->sk_state = BT_CONNECTED;
>
> /* Wake up parent */
> parent->sk_data_ready(parent, 1);
> @@ -912,6 +969,32 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
> return lm;
> }
>
> +int sco_defer(struct hci_dev *hdev, bdaddr_t *bdaddr)
> +{
> + struct sock *sk;
> + struct hlist_node *node;
> + int defer = 0;
> +
> + BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
> +
> + /* Find listening sockets */
> + read_lock(&sco_sk_list.lock);
> + sk_for_each(sk, node, &sco_sk_list.head) {
> + if (sk->sk_state != BT_LISTEN)
> + continue;
> +
> + if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
> + !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
> + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
> + defer = 1;
> + break;
> + }
> + }
> + read_unlock(&sco_sk_list.lock);
> +
> + return defer;
> +}
> +
> void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
> {
> BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
> @@ -992,7 +1075,7 @@ static const struct proto_ops sco_sock_ops = {
> .accept = sco_sock_accept,
> .getname = sco_sock_getname,
> .sendmsg = sco_sock_sendmsg,
> - .recvmsg = bt_sock_recvmsg,
> + .recvmsg = sco_sock_recvmsg,
> .poll = bt_sock_poll,
> .ioctl = bt_sock_ioctl,
> .mmap = sock_no_mmap,
> @@ -1036,7 +1119,6 @@ int __init sco_init(void)
> BT_ERR("Failed to create SCO debug file");
> }
>
> - BT_INFO("SCO socket layer initialized");
>
> return 0;
>
next prev parent reply other threads:[~2012-11-14 10:09 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-11-13 18:20 [RFC] sco: BT_DEFER_SETUP for SCO sockets Frédéric Dalleau
2012-11-13 18:20 ` [RFC] Bluetooth: Add BT_DEFER_SETUP option to sco socket Frédéric Dalleau
2012-11-13 18:45 ` Luiz Augusto von Dentz
2012-11-14 8:26 ` Michael Knudsen
2012-11-14 10:10 ` Frédéric Dalleau
2012-11-14 14:39 ` Marcel Holtmann
2012-11-14 9:17 ` Andrei Emeltchenko
2012-11-14 10:09 ` Arnaud Mouiche [this message]
2012-11-14 10:18 ` Frédéric Dalleau
2012-11-14 10:33 ` Arnaud Mouiche
2012-11-14 10:21 ` Michael Knudsen
2012-11-15 20:30 ` Gustavo Padovan
2012-11-16 12:10 ` Frédéric Dalleau
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=50A36DD1.1080507@invoxia.com \
--to=arnaud.mouiche@invoxia.com \
--cc=frederic.dalleau@linux.intel.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).