diff options
author | Frédéric Dalleau <frederic.dalleau@linux.intel.com> | 2012-11-21 04:51:12 -0500 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2012-12-03 12:59:58 -0500 |
commit | 20714bfef84d3e690c9c6f8e9cd46543b5ae1eed (patch) | |
tree | aa1ac5c6a0b959382ed2c6a2be52b45414d4cf08 /net/bluetooth/sco.c | |
parent | b96e9c671b05f95126753a22145d4509d45ca197 (diff) |
Bluetooth: Implement deferred sco socket setup
In order to authenticate and configure an incoming SCO connection, the
BT_DEFER_SETUP option was added. This option is intended to defer reply
to Connect Request on SCO sockets.
When a 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.
Signed-off-by: Frédéric Dalleau <frederic.dalleau@linux.intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth/sco.c')
-rw-r--r-- | net/bluetooth/sco.c | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c6678f2bffc9..eea17cdcaf7f 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c | |||
@@ -397,6 +397,7 @@ static void sco_sock_init(struct sock *sk, struct sock *parent) | |||
397 | 397 | ||
398 | if (parent) { | 398 | if (parent) { |
399 | sk->sk_type = parent->sk_type; | 399 | sk->sk_type = parent->sk_type; |
400 | bt_sk(sk)->flags = bt_sk(parent)->flags; | ||
400 | security_sk_clone(parent, sk); | 401 | security_sk_clone(parent, sk); |
401 | } | 402 | } |
402 | } | 403 | } |
@@ -662,6 +663,28 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
662 | return err; | 663 | return err; |
663 | } | 664 | } |
664 | 665 | ||
666 | static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | ||
667 | struct msghdr *msg, size_t len, int flags) | ||
668 | { | ||
669 | struct sock *sk = sock->sk; | ||
670 | struct sco_pinfo *pi = sco_pi(sk); | ||
671 | |||
672 | lock_sock(sk); | ||
673 | |||
674 | if (sk->sk_state == BT_CONNECT2 && | ||
675 | test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { | ||
676 | hci_conn_accept(pi->conn->hcon, 0); | ||
677 | sk->sk_state = BT_CONFIG; | ||
678 | |||
679 | release_sock(sk); | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | release_sock(sk); | ||
684 | |||
685 | return bt_sock_recvmsg(iocb, sock, msg, len, flags); | ||
686 | } | ||
687 | |||
665 | static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) | 688 | static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) |
666 | { | 689 | { |
667 | struct sock *sk = sock->sk; | 690 | struct sock *sk = sock->sk; |
@@ -906,7 +929,10 @@ static void sco_conn_ready(struct sco_conn *conn) | |||
906 | hci_conn_hold(conn->hcon); | 929 | hci_conn_hold(conn->hcon); |
907 | __sco_chan_add(conn, sk, parent); | 930 | __sco_chan_add(conn, sk, parent); |
908 | 931 | ||
909 | sk->sk_state = BT_CONNECTED; | 932 | if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) |
933 | sk->sk_state = BT_CONNECT2; | ||
934 | else | ||
935 | sk->sk_state = BT_CONNECTED; | ||
910 | 936 | ||
911 | /* Wake up parent */ | 937 | /* Wake up parent */ |
912 | parent->sk_data_ready(parent, 1); | 938 | parent->sk_data_ready(parent, 1); |
@@ -919,7 +945,7 @@ done: | |||
919 | } | 945 | } |
920 | 946 | ||
921 | /* ----- SCO interface with lower layer (HCI) ----- */ | 947 | /* ----- SCO interface with lower layer (HCI) ----- */ |
922 | int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) | 948 | int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) |
923 | { | 949 | { |
924 | struct sock *sk; | 950 | struct sock *sk; |
925 | struct hlist_node *node; | 951 | struct hlist_node *node; |
@@ -936,6 +962,9 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) | |||
936 | if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) || | 962 | if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) || |
937 | !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { | 963 | !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { |
938 | lm |= HCI_LM_ACCEPT; | 964 | lm |= HCI_LM_ACCEPT; |
965 | |||
966 | if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) | ||
967 | *flags |= HCI_PROTO_DEFER; | ||
939 | break; | 968 | break; |
940 | } | 969 | } |
941 | } | 970 | } |
@@ -1024,7 +1053,7 @@ static const struct proto_ops sco_sock_ops = { | |||
1024 | .accept = sco_sock_accept, | 1053 | .accept = sco_sock_accept, |
1025 | .getname = sco_sock_getname, | 1054 | .getname = sco_sock_getname, |
1026 | .sendmsg = sco_sock_sendmsg, | 1055 | .sendmsg = sco_sock_sendmsg, |
1027 | .recvmsg = bt_sock_recvmsg, | 1056 | .recvmsg = sco_sock_recvmsg, |
1028 | .poll = bt_sock_poll, | 1057 | .poll = bt_sock_poll, |
1029 | .ioctl = bt_sock_ioctl, | 1058 | .ioctl = bt_sock_ioctl, |
1030 | .mmap = sock_no_mmap, | 1059 | .mmap = sock_no_mmap, |