diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-01-15 15:57:00 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-02-27 00:14:24 -0500 |
commit | f66dc81f44d918ee1aa1a9d821bb2f25c7592bc0 (patch) | |
tree | fe9030b58a7fac0d85dbed2da9f33702aab2e9b5 /net/bluetooth/l2cap.c | |
parent | bb23c0ab824653be4aa7dfca15b07b3059717004 (diff) |
Bluetooth: Add support for deferring L2CAP connection setup
In order to decide if listening L2CAP 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.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 110 |
1 files changed, 101 insertions, 9 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index df1a95e185c6..123efb46d3f5 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -372,9 +372,17 @@ static void l2cap_conn_start(struct l2cap_conn *conn) | |||
372 | rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); | 372 | rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); |
373 | 373 | ||
374 | if (l2cap_check_link_mode(sk)) { | 374 | if (l2cap_check_link_mode(sk)) { |
375 | sk->sk_state = BT_CONFIG; | 375 | if (bt_sk(sk)->defer_setup) { |
376 | rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); | 376 | struct sock *parent = bt_sk(sk)->parent; |
377 | rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); | 377 | rsp.result = cpu_to_le16(L2CAP_CR_PEND); |
378 | rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); | ||
379 | parent->sk_data_ready(parent, 0); | ||
380 | |||
381 | } else { | ||
382 | sk->sk_state = BT_CONFIG; | ||
383 | rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); | ||
384 | rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); | ||
385 | } | ||
378 | } else { | 386 | } else { |
379 | rsp.result = cpu_to_le16(L2CAP_CR_PEND); | 387 | rsp.result = cpu_to_le16(L2CAP_CR_PEND); |
380 | rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); | 388 | rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); |
@@ -608,7 +616,6 @@ static void __l2cap_sock_close(struct sock *sk, int reason) | |||
608 | 616 | ||
609 | case BT_CONNECTED: | 617 | case BT_CONNECTED: |
610 | case BT_CONFIG: | 618 | case BT_CONFIG: |
611 | case BT_CONNECT2: | ||
612 | if (sk->sk_type == SOCK_SEQPACKET) { | 619 | if (sk->sk_type == SOCK_SEQPACKET) { |
613 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; | 620 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; |
614 | struct l2cap_disconn_req req; | 621 | struct l2cap_disconn_req req; |
@@ -624,6 +631,27 @@ static void __l2cap_sock_close(struct sock *sk, int reason) | |||
624 | l2cap_chan_del(sk, reason); | 631 | l2cap_chan_del(sk, reason); |
625 | break; | 632 | break; |
626 | 633 | ||
634 | case BT_CONNECT2: | ||
635 | if (sk->sk_type == SOCK_SEQPACKET) { | ||
636 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; | ||
637 | struct l2cap_conn_rsp rsp; | ||
638 | __u16 result; | ||
639 | |||
640 | if (bt_sk(sk)->defer_setup) | ||
641 | result = L2CAP_CR_SEC_BLOCK; | ||
642 | else | ||
643 | result = L2CAP_CR_BAD_PSM; | ||
644 | |||
645 | rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); | ||
646 | rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); | ||
647 | rsp.result = cpu_to_le16(result); | ||
648 | rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); | ||
649 | l2cap_send_cmd(conn, l2cap_pi(sk)->ident, | ||
650 | L2CAP_CONN_RSP, sizeof(rsp), &rsp); | ||
651 | } else | ||
652 | l2cap_chan_del(sk, reason); | ||
653 | break; | ||
654 | |||
627 | case BT_CONNECT: | 655 | case BT_CONNECT: |
628 | case BT_DISCONN: | 656 | case BT_DISCONN: |
629 | l2cap_chan_del(sk, reason); | 657 | l2cap_chan_del(sk, reason); |
@@ -653,6 +681,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) | |||
653 | 681 | ||
654 | if (parent) { | 682 | if (parent) { |
655 | sk->sk_type = parent->sk_type; | 683 | sk->sk_type = parent->sk_type; |
684 | bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; | ||
685 | |||
656 | pi->imtu = l2cap_pi(parent)->imtu; | 686 | pi->imtu = l2cap_pi(parent)->imtu; |
657 | pi->omtu = l2cap_pi(parent)->omtu; | 687 | pi->omtu = l2cap_pi(parent)->omtu; |
658 | pi->link_mode = l2cap_pi(parent)->link_mode; | 688 | pi->link_mode = l2cap_pi(parent)->link_mode; |
@@ -1106,6 +1136,33 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms | |||
1106 | return err; | 1136 | return err; |
1107 | } | 1137 | } |
1108 | 1138 | ||
1139 | static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags) | ||
1140 | { | ||
1141 | struct sock *sk = sock->sk; | ||
1142 | |||
1143 | lock_sock(sk); | ||
1144 | |||
1145 | if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { | ||
1146 | struct l2cap_conn_rsp rsp; | ||
1147 | |||
1148 | sk->sk_state = BT_CONFIG; | ||
1149 | |||
1150 | rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); | ||
1151 | rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); | ||
1152 | rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); | ||
1153 | rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); | ||
1154 | l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident, | ||
1155 | L2CAP_CONN_RSP, sizeof(rsp), &rsp); | ||
1156 | |||
1157 | release_sock(sk); | ||
1158 | return 0; | ||
1159 | } | ||
1160 | |||
1161 | release_sock(sk); | ||
1162 | |||
1163 | return bt_sock_recvmsg(iocb, sock, msg, len, flags); | ||
1164 | } | ||
1165 | |||
1109 | static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen) | 1166 | static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen) |
1110 | { | 1167 | { |
1111 | struct sock *sk = sock->sk; | 1168 | struct sock *sk = sock->sk; |
@@ -1156,6 +1213,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch | |||
1156 | { | 1213 | { |
1157 | struct sock *sk = sock->sk; | 1214 | struct sock *sk = sock->sk; |
1158 | int err = 0; | 1215 | int err = 0; |
1216 | u32 opt; | ||
1159 | 1217 | ||
1160 | BT_DBG("sk %p", sk); | 1218 | BT_DBG("sk %p", sk); |
1161 | 1219 | ||
@@ -1165,6 +1223,20 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch | |||
1165 | lock_sock(sk); | 1223 | lock_sock(sk); |
1166 | 1224 | ||
1167 | switch (optname) { | 1225 | switch (optname) { |
1226 | case BT_DEFER_SETUP: | ||
1227 | if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { | ||
1228 | err = -EINVAL; | ||
1229 | break; | ||
1230 | } | ||
1231 | |||
1232 | if (get_user(opt, (u32 __user *) optval)) { | ||
1233 | err = -EFAULT; | ||
1234 | break; | ||
1235 | } | ||
1236 | |||
1237 | bt_sk(sk)->defer_setup = opt; | ||
1238 | break; | ||
1239 | |||
1168 | default: | 1240 | default: |
1169 | err = -ENOPROTOOPT; | 1241 | err = -ENOPROTOOPT; |
1170 | break; | 1242 | break; |
@@ -1207,7 +1279,9 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us | |||
1207 | break; | 1279 | break; |
1208 | 1280 | ||
1209 | case L2CAP_CONNINFO: | 1281 | case L2CAP_CONNINFO: |
1210 | if (sk->sk_state != BT_CONNECTED) { | 1282 | if (sk->sk_state != BT_CONNECTED && |
1283 | !(sk->sk_state == BT_CONNECT2 && | ||
1284 | bt_sk(sk)->defer_setup)) { | ||
1211 | err = -ENOTCONN; | 1285 | err = -ENOTCONN; |
1212 | break; | 1286 | break; |
1213 | } | 1287 | } |
@@ -1246,6 +1320,17 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch | |||
1246 | lock_sock(sk); | 1320 | lock_sock(sk); |
1247 | 1321 | ||
1248 | switch (optname) { | 1322 | switch (optname) { |
1323 | case BT_DEFER_SETUP: | ||
1324 | if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { | ||
1325 | err = -EINVAL; | ||
1326 | break; | ||
1327 | } | ||
1328 | |||
1329 | if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) | ||
1330 | err = -EFAULT; | ||
1331 | |||
1332 | break; | ||
1333 | |||
1249 | default: | 1334 | default: |
1250 | err = -ENOPROTOOPT; | 1335 | err = -ENOPROTOOPT; |
1251 | break; | 1336 | break; |
@@ -1670,9 +1755,16 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd | |||
1670 | 1755 | ||
1671 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { | 1756 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { |
1672 | if (l2cap_check_link_mode(sk)) { | 1757 | if (l2cap_check_link_mode(sk)) { |
1673 | sk->sk_state = BT_CONFIG; | 1758 | if (bt_sk(sk)->defer_setup) { |
1674 | result = L2CAP_CR_SUCCESS; | 1759 | sk->sk_state = BT_CONNECT2; |
1675 | status = L2CAP_CS_NO_INFO; | 1760 | result = L2CAP_CR_PEND; |
1761 | status = L2CAP_CS_AUTHOR_PEND; | ||
1762 | parent->sk_data_ready(parent, 0); | ||
1763 | } else { | ||
1764 | sk->sk_state = BT_CONFIG; | ||
1765 | result = L2CAP_CR_SUCCESS; | ||
1766 | status = L2CAP_CS_NO_INFO; | ||
1767 | } | ||
1676 | } else { | 1768 | } else { |
1677 | sk->sk_state = BT_CONNECT2; | 1769 | sk->sk_state = BT_CONNECT2; |
1678 | result = L2CAP_CR_PEND; | 1770 | result = L2CAP_CR_PEND; |
@@ -2494,7 +2586,7 @@ static const struct proto_ops l2cap_sock_ops = { | |||
2494 | .accept = l2cap_sock_accept, | 2586 | .accept = l2cap_sock_accept, |
2495 | .getname = l2cap_sock_getname, | 2587 | .getname = l2cap_sock_getname, |
2496 | .sendmsg = l2cap_sock_sendmsg, | 2588 | .sendmsg = l2cap_sock_sendmsg, |
2497 | .recvmsg = bt_sock_recvmsg, | 2589 | .recvmsg = l2cap_sock_recvmsg, |
2498 | .poll = bt_sock_poll, | 2590 | .poll = bt_sock_poll, |
2499 | .ioctl = bt_sock_ioctl, | 2591 | .ioctl = bt_sock_ioctl, |
2500 | .mmap = sock_no_mmap, | 2592 | .mmap = sock_no_mmap, |