Skip to content

Commit 09572fc

Browse files
Vudentzholtmann
authored andcommitted
Bluetooth: hci_sock: Add support for BT_{SND,RCV}BUF
This adds support for BT_{SND,RCV}BUF so userspace can set MTU based on the channel usage. Fixes: bluez/bluez#201 Signed-off-by: Luiz Augusto von Dentz <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent 01ce70b commit 09572fc

File tree

1 file changed

+91
-11
lines changed

1 file changed

+91
-11
lines changed

net/bluetooth/hci_sock.c

Lines changed: 91 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct hci_pinfo {
5757
unsigned long flags;
5858
__u32 cookie;
5959
char comm[TASK_COMM_LEN];
60+
__u16 mtu;
6061
};
6162

6263
static struct hci_dev *hci_hdev_from_sock(struct sock *sk)
@@ -1374,6 +1375,10 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
13741375
break;
13751376
}
13761377

1378+
/* Default MTU to HCI_MAX_FRAME_SIZE if not set */
1379+
if (!hci_pi(sk)->mtu)
1380+
hci_pi(sk)->mtu = HCI_MAX_FRAME_SIZE;
1381+
13771382
sk->sk_state = BT_BOUND;
13781383

13791384
done:
@@ -1719,7 +1724,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
17191724
if (flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL | MSG_ERRQUEUE | MSG_CMSG_COMPAT))
17201725
return -EINVAL;
17211726

1722-
if (len < 4 || len > HCI_MAX_FRAME_SIZE)
1727+
if (len < 4 || len > hci_pi(sk)->mtu)
17231728
return -EINVAL;
17241729

17251730
buf = kmalloc(len, GFP_KERNEL);
@@ -1849,18 +1854,15 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
18491854
goto done;
18501855
}
18511856

1852-
static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
1853-
sockptr_t optval, unsigned int len)
1857+
static int hci_sock_setsockopt_old(struct socket *sock, int level, int optname,
1858+
sockptr_t optval, unsigned int len)
18541859
{
18551860
struct hci_ufilter uf = { .opcode = 0 };
18561861
struct sock *sk = sock->sk;
18571862
int err = 0, opt = 0;
18581863

18591864
BT_DBG("sk %p, opt %d", sk, optname);
18601865

1861-
if (level != SOL_HCI)
1862-
return -ENOPROTOOPT;
1863-
18641866
lock_sock(sk);
18651867

18661868
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
@@ -1935,18 +1937,63 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
19351937
return err;
19361938
}
19371939

1938-
static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
1939-
char __user *optval, int __user *optlen)
1940+
static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
1941+
sockptr_t optval, unsigned int len)
19401942
{
1941-
struct hci_ufilter uf;
19421943
struct sock *sk = sock->sk;
1943-
int len, opt, err = 0;
1944+
int err = 0, opt = 0;
19441945

19451946
BT_DBG("sk %p, opt %d", sk, optname);
19461947

1947-
if (level != SOL_HCI)
1948+
if (level == SOL_HCI)
1949+
return hci_sock_setsockopt_old(sock, level, optname, optval,
1950+
len);
1951+
1952+
if (level != SOL_BLUETOOTH)
19481953
return -ENOPROTOOPT;
19491954

1955+
lock_sock(sk);
1956+
1957+
switch (optname) {
1958+
case BT_SNDMTU:
1959+
case BT_RCVMTU:
1960+
switch (hci_pi(sk)->channel) {
1961+
/* Don't allow changing MTU for channels that are meant for HCI
1962+
* traffic only.
1963+
*/
1964+
case HCI_CHANNEL_RAW:
1965+
case HCI_CHANNEL_USER:
1966+
err = -ENOPROTOOPT;
1967+
goto done;
1968+
}
1969+
1970+
if (copy_from_sockptr(&opt, optval, sizeof(u16))) {
1971+
err = -EFAULT;
1972+
break;
1973+
}
1974+
1975+
hci_pi(sk)->mtu = opt;
1976+
break;
1977+
1978+
default:
1979+
err = -ENOPROTOOPT;
1980+
break;
1981+
}
1982+
1983+
done:
1984+
release_sock(sk);
1985+
return err;
1986+
}
1987+
1988+
static int hci_sock_getsockopt_old(struct socket *sock, int level, int optname,
1989+
char __user *optval, int __user *optlen)
1990+
{
1991+
struct hci_ufilter uf;
1992+
struct sock *sk = sock->sk;
1993+
int len, opt, err = 0;
1994+
1995+
BT_DBG("sk %p, opt %d", sk, optname);
1996+
19501997
if (get_user(len, optlen))
19511998
return -EFAULT;
19521999

@@ -2004,6 +2051,39 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
20042051
return err;
20052052
}
20062053

2054+
static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
2055+
char __user *optval, int __user *optlen)
2056+
{
2057+
struct sock *sk = sock->sk;
2058+
int err = 0;
2059+
2060+
BT_DBG("sk %p, opt %d", sk, optname);
2061+
2062+
if (level == SOL_HCI)
2063+
return hci_sock_getsockopt_old(sock, level, optname, optval,
2064+
optlen);
2065+
2066+
if (level != SOL_BLUETOOTH)
2067+
return -ENOPROTOOPT;
2068+
2069+
lock_sock(sk);
2070+
2071+
switch (optname) {
2072+
case BT_SNDMTU:
2073+
case BT_RCVMTU:
2074+
if (put_user(hci_pi(sk)->mtu, (u16 __user *)optval))
2075+
err = -EFAULT;
2076+
break;
2077+
2078+
default:
2079+
err = -ENOPROTOOPT;
2080+
break;
2081+
}
2082+
2083+
release_sock(sk);
2084+
return err;
2085+
}
2086+
20072087
static const struct proto_ops hci_sock_ops = {
20082088
.family = PF_BLUETOOTH,
20092089
.owner = THIS_MODULE,

0 commit comments

Comments
 (0)