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 | |
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')
-rw-r--r-- | net/bluetooth/rfcomm/core.c | 56 | ||||
-rw-r--r-- | net/bluetooth/rfcomm/sock.c | 44 |
2 files changed, 84 insertions, 16 deletions
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index acd84fd524b8..edee49e00fbf 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
@@ -421,9 +421,16 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) | |||
421 | d, d->state, d->dlci, err, s); | 421 | d, d->state, d->dlci, err, s); |
422 | 422 | ||
423 | switch (d->state) { | 423 | switch (d->state) { |
424 | case BT_CONNECTED: | ||
425 | case BT_CONFIG: | ||
426 | case BT_CONNECT: | 424 | case BT_CONNECT: |
425 | case BT_CONFIG: | ||
426 | if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { | ||
427 | set_bit(RFCOMM_AUTH_REJECT, &d->flags); | ||
428 | rfcomm_schedule(RFCOMM_SCHED_AUTH); | ||
429 | break; | ||
430 | } | ||
431 | /* Fall through */ | ||
432 | |||
433 | case BT_CONNECTED: | ||
427 | d->state = BT_DISCONN; | 434 | d->state = BT_DISCONN; |
428 | if (skb_queue_empty(&d->tx_queue)) { | 435 | if (skb_queue_empty(&d->tx_queue)) { |
429 | rfcomm_send_disc(s, d->dlci); | 436 | rfcomm_send_disc(s, d->dlci); |
@@ -434,6 +441,14 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) | |||
434 | } | 441 | } |
435 | break; | 442 | break; |
436 | 443 | ||
444 | case BT_OPEN: | ||
445 | if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) { | ||
446 | set_bit(RFCOMM_AUTH_REJECT, &d->flags); | ||
447 | rfcomm_schedule(RFCOMM_SCHED_AUTH); | ||
448 | break; | ||
449 | } | ||
450 | /* Fall through */ | ||
451 | |||
437 | default: | 452 | default: |
438 | rfcomm_dlc_clear_timer(d); | 453 | rfcomm_dlc_clear_timer(d); |
439 | 454 | ||
@@ -1162,7 +1177,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) | |||
1162 | return 0; | 1177 | return 0; |
1163 | } | 1178 | } |
1164 | 1179 | ||
1165 | static void rfcomm_dlc_accept(struct rfcomm_dlc *d) | 1180 | void rfcomm_dlc_accept(struct rfcomm_dlc *d) |
1166 | { | 1181 | { |
1167 | struct sock *sk = d->session->sock->sk; | 1182 | struct sock *sk = d->session->sock->sk; |
1168 | 1183 | ||
@@ -1181,6 +1196,20 @@ static void rfcomm_dlc_accept(struct rfcomm_dlc *d) | |||
1181 | rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); | 1196 | rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); |
1182 | } | 1197 | } |
1183 | 1198 | ||
1199 | static void rfcomm_check_accept(struct rfcomm_dlc *d) | ||
1200 | { | ||
1201 | if (rfcomm_check_link_mode(d)) { | ||
1202 | set_bit(RFCOMM_AUTH_PENDING, &d->flags); | ||
1203 | rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); | ||
1204 | } else { | ||
1205 | if (d->defer_setup) { | ||
1206 | set_bit(RFCOMM_DEFER_SETUP, &d->flags); | ||
1207 | rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); | ||
1208 | } else | ||
1209 | rfcomm_dlc_accept(d); | ||
1210 | } | ||
1211 | } | ||
1212 | |||
1184 | static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) | 1213 | static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) |
1185 | { | 1214 | { |
1186 | struct rfcomm_dlc *d; | 1215 | struct rfcomm_dlc *d; |
@@ -1203,11 +1232,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) | |||
1203 | if (d) { | 1232 | if (d) { |
1204 | if (d->state == BT_OPEN) { | 1233 | if (d->state == BT_OPEN) { |
1205 | /* DLC was previously opened by PN request */ | 1234 | /* DLC was previously opened by PN request */ |
1206 | if (rfcomm_check_link_mode(d)) { | 1235 | rfcomm_check_accept(d); |
1207 | set_bit(RFCOMM_AUTH_PENDING, &d->flags); | ||
1208 | rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); | ||
1209 | } else | ||
1210 | rfcomm_dlc_accept(d); | ||
1211 | } | 1236 | } |
1212 | return 0; | 1237 | return 0; |
1213 | } | 1238 | } |
@@ -1219,11 +1244,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) | |||
1219 | d->addr = __addr(s->initiator, dlci); | 1244 | d->addr = __addr(s->initiator, dlci); |
1220 | rfcomm_dlc_link(s, d); | 1245 | rfcomm_dlc_link(s, d); |
1221 | 1246 | ||
1222 | if (rfcomm_check_link_mode(d)) { | 1247 | rfcomm_check_accept(d); |
1223 | set_bit(RFCOMM_AUTH_PENDING, &d->flags); | ||
1224 | rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); | ||
1225 | } else | ||
1226 | rfcomm_dlc_accept(d); | ||
1227 | } else { | 1248 | } else { |
1228 | rfcomm_send_dm(s, dlci); | 1249 | rfcomm_send_dm(s, dlci); |
1229 | } | 1250 | } |
@@ -1717,8 +1738,13 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) | |||
1717 | if (d->out) { | 1738 | if (d->out) { |
1718 | rfcomm_send_pn(s, 1, d); | 1739 | rfcomm_send_pn(s, 1, d); |
1719 | rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT); | 1740 | rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT); |
1720 | } else | 1741 | } else { |
1721 | rfcomm_dlc_accept(d); | 1742 | if (d->defer_setup) { |
1743 | set_bit(RFCOMM_DEFER_SETUP, &d->flags); | ||
1744 | rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); | ||
1745 | } else | ||
1746 | rfcomm_dlc_accept(d); | ||
1747 | } | ||
1722 | if (d->link_mode & RFCOMM_LM_SECURE) { | 1748 | if (d->link_mode & RFCOMM_LM_SECURE) { |
1723 | struct sock *sk = s->sock->sk; | 1749 | struct sock *sk = s->sock->sk; |
1724 | hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon); | 1750 | hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon); |
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 | ||