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 | |
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>
-rw-r--r-- | include/net/bluetooth/hci_core.h | 9 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 52 | ||||
-rw-r--r-- | net/bluetooth/sco.c | 35 |
3 files changed, 86 insertions, 10 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ef5b85dac3f7..76891a914e75 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -376,7 +376,7 @@ extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt); | |||
376 | extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, | 376 | extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, |
377 | u16 flags); | 377 | u16 flags); |
378 | 378 | ||
379 | extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); | 379 | extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); |
380 | extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status); | 380 | extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status); |
381 | extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason); | 381 | extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason); |
382 | extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); | 382 | extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); |
@@ -577,6 +577,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); | |||
577 | int hci_conn_del(struct hci_conn *conn); | 577 | int hci_conn_del(struct hci_conn *conn); |
578 | void hci_conn_hash_flush(struct hci_dev *hdev); | 578 | void hci_conn_hash_flush(struct hci_dev *hdev); |
579 | void hci_conn_check_pending(struct hci_dev *hdev); | 579 | void hci_conn_check_pending(struct hci_dev *hdev); |
580 | void hci_conn_accept(struct hci_conn *conn, int mask); | ||
580 | 581 | ||
581 | struct hci_chan *hci_chan_create(struct hci_conn *conn); | 582 | struct hci_chan *hci_chan_create(struct hci_conn *conn); |
582 | void hci_chan_del(struct hci_chan *chan); | 583 | void hci_chan_del(struct hci_chan *chan); |
@@ -779,8 +780,10 @@ void hci_conn_del_sysfs(struct hci_conn *conn); | |||
779 | #define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR) | 780 | #define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR) |
780 | 781 | ||
781 | /* ----- HCI protocols ----- */ | 782 | /* ----- HCI protocols ----- */ |
783 | #define HCI_PROTO_DEFER 0x01 | ||
784 | |||
782 | static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, | 785 | static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, |
783 | __u8 type) | 786 | __u8 type, __u8 *flags) |
784 | { | 787 | { |
785 | switch (type) { | 788 | switch (type) { |
786 | case ACL_LINK: | 789 | case ACL_LINK: |
@@ -788,7 +791,7 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
788 | 791 | ||
789 | case SCO_LINK: | 792 | case SCO_LINK: |
790 | case ESCO_LINK: | 793 | case ESCO_LINK: |
791 | return sco_connect_ind(hdev, bdaddr); | 794 | return sco_connect_ind(hdev, bdaddr, flags); |
792 | 795 | ||
793 | default: | 796 | default: |
794 | BT_ERR("unknown link type %d", type); | 797 | BT_ERR("unknown link type %d", type); |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9f5c5f244502..3843f1897c86 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -2047,15 +2047,53 @@ unlock: | |||
2047 | hci_conn_check_pending(hdev); | 2047 | hci_conn_check_pending(hdev); |
2048 | } | 2048 | } |
2049 | 2049 | ||
2050 | void hci_conn_accept(struct hci_conn *conn, int mask) | ||
2051 | { | ||
2052 | struct hci_dev *hdev = conn->hdev; | ||
2053 | |||
2054 | BT_DBG("conn %p", conn); | ||
2055 | |||
2056 | conn->state = BT_CONFIG; | ||
2057 | |||
2058 | if (!lmp_esco_capable(hdev)) { | ||
2059 | struct hci_cp_accept_conn_req cp; | ||
2060 | |||
2061 | bacpy(&cp.bdaddr, &conn->dst); | ||
2062 | |||
2063 | if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) | ||
2064 | cp.role = 0x00; /* Become master */ | ||
2065 | else | ||
2066 | cp.role = 0x01; /* Remain slave */ | ||
2067 | |||
2068 | hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); | ||
2069 | } else /* lmp_esco_capable(hdev)) */ { | ||
2070 | struct hci_cp_accept_sync_conn_req cp; | ||
2071 | |||
2072 | bacpy(&cp.bdaddr, &conn->dst); | ||
2073 | cp.pkt_type = cpu_to_le16(conn->pkt_type); | ||
2074 | |||
2075 | cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); | ||
2076 | cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); | ||
2077 | cp.max_latency = __constant_cpu_to_le16(0xffff); | ||
2078 | cp.content_format = cpu_to_le16(hdev->voice_setting); | ||
2079 | cp.retrans_effort = 0xff; | ||
2080 | |||
2081 | hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, | ||
2082 | sizeof(cp), &cp); | ||
2083 | } | ||
2084 | } | ||
2085 | |||
2050 | static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | 2086 | static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) |
2051 | { | 2087 | { |
2052 | struct hci_ev_conn_request *ev = (void *) skb->data; | 2088 | struct hci_ev_conn_request *ev = (void *) skb->data; |
2053 | int mask = hdev->link_mode; | 2089 | int mask = hdev->link_mode; |
2090 | __u8 flags = 0; | ||
2054 | 2091 | ||
2055 | BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr, | 2092 | BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr, |
2056 | ev->link_type); | 2093 | ev->link_type); |
2057 | 2094 | ||
2058 | mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); | 2095 | mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type, |
2096 | &flags); | ||
2059 | 2097 | ||
2060 | if ((mask & HCI_LM_ACCEPT) && | 2098 | if ((mask & HCI_LM_ACCEPT) && |
2061 | !hci_blacklist_lookup(hdev, &ev->bdaddr)) { | 2099 | !hci_blacklist_lookup(hdev, &ev->bdaddr)) { |
@@ -2081,12 +2119,13 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
2081 | } | 2119 | } |
2082 | 2120 | ||
2083 | memcpy(conn->dev_class, ev->dev_class, 3); | 2121 | memcpy(conn->dev_class, ev->dev_class, 3); |
2084 | conn->state = BT_CONNECT; | ||
2085 | 2122 | ||
2086 | hci_dev_unlock(hdev); | 2123 | hci_dev_unlock(hdev); |
2087 | 2124 | ||
2088 | if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) { | 2125 | if (ev->link_type == ACL_LINK || |
2126 | (!(flags & HCI_PROTO_DEFER) && !lmp_esco_capable(hdev))) { | ||
2089 | struct hci_cp_accept_conn_req cp; | 2127 | struct hci_cp_accept_conn_req cp; |
2128 | conn->state = BT_CONNECT; | ||
2090 | 2129 | ||
2091 | bacpy(&cp.bdaddr, &ev->bdaddr); | 2130 | bacpy(&cp.bdaddr, &ev->bdaddr); |
2092 | 2131 | ||
@@ -2097,8 +2136,9 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
2097 | 2136 | ||
2098 | hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), | 2137 | hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), |
2099 | &cp); | 2138 | &cp); |
2100 | } else { | 2139 | } else if (!(flags & HCI_PROTO_DEFER)) { |
2101 | struct hci_cp_accept_sync_conn_req cp; | 2140 | struct hci_cp_accept_sync_conn_req cp; |
2141 | conn->state = BT_CONNECT; | ||
2102 | 2142 | ||
2103 | bacpy(&cp.bdaddr, &ev->bdaddr); | 2143 | bacpy(&cp.bdaddr, &ev->bdaddr); |
2104 | cp.pkt_type = cpu_to_le16(conn->pkt_type); | 2144 | cp.pkt_type = cpu_to_le16(conn->pkt_type); |
@@ -2111,6 +2151,10 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
2111 | 2151 | ||
2112 | hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, | 2152 | hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, |
2113 | sizeof(cp), &cp); | 2153 | sizeof(cp), &cp); |
2154 | } else { | ||
2155 | conn->state = BT_CONNECT2; | ||
2156 | hci_proto_connect_cfm(conn, 0); | ||
2157 | hci_conn_put(conn); | ||
2114 | } | 2158 | } |
2115 | } else { | 2159 | } else { |
2116 | /* Connection rejected */ | 2160 | /* Connection rejected */ |
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, |