diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-01-15 15:56:48 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-02-27 00:14:23 -0500 |
commit | bb23c0ab824653be4aa7dfca15b07b3059717004 (patch) | |
tree | bd0390c67d129e8b5ddc2a70a1b12e383db6fa16 /net/bluetooth/rfcomm/sock.c | |
parent | c4f912e155504e94dd4f3d63c378dab0ff03dbda (diff) |
Bluetooth: Add support for deferring RFCOMM connection setup
In order to decide if listening RFCOMM sockets should be accept()ed
the BD_ADDR of the remote device needs to be known. This patch adds
a socket option which defines a timeout for deferring the actual
connection setup.
The connection setup is done after reading from the socket for the
first time. Until then writing to the socket returns ENOTCONN.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/rfcomm/sock.c')
-rw-r--r-- | net/bluetooth/rfcomm/sock.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 65dd7133d72b..d37a829a81e4 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c | |||
@@ -262,8 +262,10 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent) | |||
262 | if (parent) { | 262 | if (parent) { |
263 | sk->sk_type = parent->sk_type; | 263 | sk->sk_type = parent->sk_type; |
264 | pi->link_mode = rfcomm_pi(parent)->link_mode; | 264 | pi->link_mode = rfcomm_pi(parent)->link_mode; |
265 | pi->dlc->defer_setup = bt_sk(parent)->defer_setup; | ||
265 | } else { | 266 | } else { |
266 | pi->link_mode = 0; | 267 | pi->link_mode = 0; |
268 | pi->dlc->defer_setup = 0; | ||
267 | } | 269 | } |
268 | 270 | ||
269 | pi->dlc->link_mode = pi->link_mode; | 271 | pi->dlc->link_mode = pi->link_mode; |
@@ -554,6 +556,9 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
554 | struct sk_buff *skb; | 556 | struct sk_buff *skb; |
555 | int sent = 0; | 557 | int sent = 0; |
556 | 558 | ||
559 | if (test_bit(RFCOMM_DEFER_SETUP, &d->flags)) | ||
560 | return -ENOTCONN; | ||
561 | |||
557 | if (msg->msg_flags & MSG_OOB) | 562 | if (msg->msg_flags & MSG_OOB) |
558 | return -EOPNOTSUPP; | 563 | return -EOPNOTSUPP; |
559 | 564 | ||
@@ -633,10 +638,16 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
633 | struct msghdr *msg, size_t size, int flags) | 638 | struct msghdr *msg, size_t size, int flags) |
634 | { | 639 | { |
635 | struct sock *sk = sock->sk; | 640 | struct sock *sk = sock->sk; |
641 | struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; | ||
636 | int err = 0; | 642 | int err = 0; |
637 | size_t target, copied = 0; | 643 | size_t target, copied = 0; |
638 | long timeo; | 644 | long timeo; |
639 | 645 | ||
646 | if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { | ||
647 | rfcomm_dlc_accept(d); | ||
648 | return 0; | ||
649 | } | ||
650 | |||
640 | if (flags & MSG_OOB) | 651 | if (flags & MSG_OOB) |
641 | return -EOPNOTSUPP; | 652 | return -EOPNOTSUPP; |
642 | 653 | ||
@@ -746,6 +757,7 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c | |||
746 | { | 757 | { |
747 | struct sock *sk = sock->sk; | 758 | struct sock *sk = sock->sk; |
748 | int err = 0; | 759 | int err = 0; |
760 | u32 opt; | ||
749 | 761 | ||
750 | BT_DBG("sk %p", sk); | 762 | BT_DBG("sk %p", sk); |
751 | 763 | ||
@@ -755,6 +767,20 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c | |||
755 | lock_sock(sk); | 767 | lock_sock(sk); |
756 | 768 | ||
757 | switch (optname) { | 769 | switch (optname) { |
770 | case BT_DEFER_SETUP: | ||
771 | if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { | ||
772 | err = -EINVAL; | ||
773 | break; | ||
774 | } | ||
775 | |||
776 | if (get_user(opt, (u32 __user *) optval)) { | ||
777 | err = -EFAULT; | ||
778 | break; | ||
779 | } | ||
780 | |||
781 | bt_sk(sk)->defer_setup = opt; | ||
782 | break; | ||
783 | |||
758 | default: | 784 | default: |
759 | err = -ENOPROTOOPT; | 785 | err = -ENOPROTOOPT; |
760 | break; | 786 | break; |
@@ -785,7 +811,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u | |||
785 | break; | 811 | break; |
786 | 812 | ||
787 | case RFCOMM_CONNINFO: | 813 | case RFCOMM_CONNINFO: |
788 | if (sk->sk_state != BT_CONNECTED) { | 814 | if (sk->sk_state != BT_CONNECTED && |
815 | !rfcomm_pi(sk)->dlc->defer_setup) { | ||
789 | err = -ENOTCONN; | 816 | err = -ENOTCONN; |
790 | break; | 817 | break; |
791 | } | 818 | } |
@@ -826,6 +853,17 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c | |||
826 | lock_sock(sk); | 853 | lock_sock(sk); |
827 | 854 | ||
828 | switch (optname) { | 855 | switch (optname) { |
856 | case BT_DEFER_SETUP: | ||
857 | if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { | ||
858 | err = -EINVAL; | ||
859 | break; | ||
860 | } | ||
861 | |||
862 | if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) | ||
863 | err = -EFAULT; | ||
864 | |||
865 | break; | ||
866 | |||
829 | default: | 867 | default: |
830 | err = -ENOPROTOOPT; | 868 | err = -ENOPROTOOPT; |
831 | break; | 869 | break; |
@@ -938,6 +976,10 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * | |||
938 | 976 | ||
939 | done: | 977 | done: |
940 | bh_unlock_sock(parent); | 978 | bh_unlock_sock(parent); |
979 | |||
980 | if (bt_sk(parent)->defer_setup) | ||
981 | parent->sk_state_change(parent); | ||
982 | |||
941 | return result; | 983 | return result; |
942 | } | 984 | } |
943 | 985 | ||