]>
Commit | Line | Data |
---|---|---|
7f87a3cd SL |
1 | From 7e59316473bc029ca3bfcea291cd36332f76dd57 Mon Sep 17 00:00:00 2001 |
2 | From: Sasha Levin <sashal@kernel.org> | |
3 | Date: Tue, 7 Sep 2021 15:42:42 +0530 | |
4 | Subject: Bluetooth: Allow setting of codec for HFP offload use case | |
5 | ||
6 | From: Kiran K <kiran.k@intel.com> | |
7 | ||
8 | [ Upstream commit f6873401a60865702069fb2e3f67671fff9c082c ] | |
9 | ||
10 | This patch allows user space to set the codec that needs to | |
11 | be used for HFP offload use case. The codec details are cached and | |
12 | the controller is configured before opening the SCO connection. | |
13 | ||
14 | Signed-off-by: Kiran K <kiran.k@intel.com> | |
15 | Reviewed-by: Chethan T N <chethan.tumkur.narayan@intel.com> | |
16 | Reviewed-by: Srivatsa Ravishankar <ravishankar.srivatsa@intel.com> | |
17 | Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | |
18 | Stable-dep-of: 51eda36d33e4 ("Bluetooth: SCO: Fix not validating setsockopt user input") | |
19 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
20 | --- | |
21 | include/net/bluetooth/bluetooth.h | 2 ++ | |
22 | net/bluetooth/sco.c | 60 +++++++++++++++++++++++++++++++ | |
23 | 2 files changed, 62 insertions(+) | |
24 | ||
25 | diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h | |
26 | index 8700635f08a69..4191edbb0641d 100644 | |
27 | --- a/include/net/bluetooth/bluetooth.h | |
28 | +++ b/include/net/bluetooth/bluetooth.h | |
29 | @@ -173,6 +173,8 @@ struct bt_codecs { | |
30 | struct bt_codec codecs[]; | |
31 | } __packed; | |
32 | ||
33 | +#define BT_CODEC_CVSD 0x02 | |
34 | + | |
35 | __printf(1, 2) | |
36 | void bt_info(const char *fmt, ...); | |
37 | __printf(1, 2) | |
38 | diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c | |
39 | index 5e518a6d5e13d..cef26f1d8a583 100644 | |
40 | --- a/net/bluetooth/sco.c | |
41 | +++ b/net/bluetooth/sco.c | |
42 | @@ -69,6 +69,7 @@ struct sco_pinfo { | |
43 | __u32 flags; | |
44 | __u16 setting; | |
45 | __u8 cmsg_mask; | |
46 | + struct bt_codec codec; | |
47 | struct sco_conn *conn; | |
48 | }; | |
49 | ||
50 | @@ -434,6 +435,7 @@ static void __sco_sock_close(struct sock *sk) | |
51 | sock_set_flag(sk, SOCK_ZAPPED); | |
52 | break; | |
53 | } | |
54 | + | |
55 | } | |
56 | ||
57 | /* Must be called on unlocked socket. */ | |
58 | @@ -494,6 +496,10 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, | |
59 | sk->sk_state = BT_OPEN; | |
60 | ||
61 | sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT; | |
62 | + sco_pi(sk)->codec.id = BT_CODEC_CVSD; | |
63 | + sco_pi(sk)->codec.cid = 0xffff; | |
64 | + sco_pi(sk)->codec.vid = 0xffff; | |
65 | + sco_pi(sk)->codec.data_path = 0x00; | |
66 | ||
67 | bt_sock_link(&sco_sk_list, sk); | |
68 | return sk; | |
69 | @@ -828,6 +834,9 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, | |
70 | int len, err = 0; | |
71 | struct bt_voice voice; | |
72 | u32 opt; | |
73 | + struct bt_codecs *codecs; | |
74 | + struct hci_dev *hdev; | |
75 | + __u8 buffer[255]; | |
76 | ||
77 | BT_DBG("sk %p", sk); | |
78 | ||
79 | @@ -889,6 +898,57 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, | |
80 | sco_pi(sk)->cmsg_mask &= SCO_CMSG_PKT_STATUS; | |
81 | break; | |
82 | ||
83 | + case BT_CODEC: | |
84 | + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND && | |
85 | + sk->sk_state != BT_CONNECT2) { | |
86 | + err = -EINVAL; | |
87 | + break; | |
88 | + } | |
89 | + | |
90 | + hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, | |
91 | + BDADDR_BREDR); | |
92 | + if (!hdev) { | |
93 | + err = -EBADFD; | |
94 | + break; | |
95 | + } | |
96 | + | |
97 | + if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) { | |
98 | + hci_dev_put(hdev); | |
99 | + err = -EOPNOTSUPP; | |
100 | + break; | |
101 | + } | |
102 | + | |
103 | + if (!hdev->get_data_path_id) { | |
104 | + hci_dev_put(hdev); | |
105 | + err = -EOPNOTSUPP; | |
106 | + break; | |
107 | + } | |
108 | + | |
109 | + if (optlen < sizeof(struct bt_codecs) || | |
110 | + optlen > sizeof(buffer)) { | |
111 | + hci_dev_put(hdev); | |
112 | + err = -EINVAL; | |
113 | + break; | |
114 | + } | |
115 | + | |
116 | + if (copy_from_sockptr(buffer, optval, optlen)) { | |
117 | + hci_dev_put(hdev); | |
118 | + err = -EFAULT; | |
119 | + break; | |
120 | + } | |
121 | + | |
122 | + codecs = (void *)buffer; | |
123 | + | |
124 | + if (codecs->num_codecs > 1) { | |
125 | + hci_dev_put(hdev); | |
126 | + err = -EINVAL; | |
127 | + break; | |
128 | + } | |
129 | + | |
130 | + sco_pi(sk)->codec = codecs->codecs[0]; | |
131 | + hci_dev_put(hdev); | |
132 | + break; | |
133 | + | |
134 | default: | |
135 | err = -ENOPROTOOPT; | |
136 | break; | |
137 | -- | |
138 | 2.43.0 | |
139 |