Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/bluetooth/hidp/sock.c
15109 views
1
/*
2
HIDP implementation for Linux Bluetooth stack (BlueZ).
3
Copyright (C) 2003-2004 Marcel Holtmann <[email protected]>
4
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License version 2 as
7
published by the Free Software Foundation;
8
9
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20
SOFTWARE IS DISCLAIMED.
21
*/
22
23
#include <linux/module.h>
24
25
#include <linux/types.h>
26
#include <linux/capability.h>
27
#include <linux/errno.h>
28
#include <linux/kernel.h>
29
#include <linux/poll.h>
30
#include <linux/fcntl.h>
31
#include <linux/skbuff.h>
32
#include <linux/socket.h>
33
#include <linux/ioctl.h>
34
#include <linux/file.h>
35
#include <linux/init.h>
36
#include <linux/compat.h>
37
#include <linux/gfp.h>
38
#include <net/sock.h>
39
40
#include "hidp.h"
41
42
static int hidp_sock_release(struct socket *sock)
43
{
44
struct sock *sk = sock->sk;
45
46
BT_DBG("sock %p sk %p", sock, sk);
47
48
if (!sk)
49
return 0;
50
51
sock_orphan(sk);
52
sock_put(sk);
53
54
return 0;
55
}
56
57
static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
58
{
59
void __user *argp = (void __user *) arg;
60
struct hidp_connadd_req ca;
61
struct hidp_conndel_req cd;
62
struct hidp_connlist_req cl;
63
struct hidp_conninfo ci;
64
struct socket *csock;
65
struct socket *isock;
66
int err;
67
68
BT_DBG("cmd %x arg %lx", cmd, arg);
69
70
switch (cmd) {
71
case HIDPCONNADD:
72
if (!capable(CAP_NET_ADMIN))
73
return -EACCES;
74
75
if (copy_from_user(&ca, argp, sizeof(ca)))
76
return -EFAULT;
77
78
csock = sockfd_lookup(ca.ctrl_sock, &err);
79
if (!csock)
80
return err;
81
82
isock = sockfd_lookup(ca.intr_sock, &err);
83
if (!isock) {
84
sockfd_put(csock);
85
return err;
86
}
87
88
if (csock->sk->sk_state != BT_CONNECTED ||
89
isock->sk->sk_state != BT_CONNECTED) {
90
sockfd_put(csock);
91
sockfd_put(isock);
92
return -EBADFD;
93
}
94
95
err = hidp_add_connection(&ca, csock, isock);
96
if (!err) {
97
if (copy_to_user(argp, &ca, sizeof(ca)))
98
err = -EFAULT;
99
} else {
100
sockfd_put(csock);
101
sockfd_put(isock);
102
}
103
104
return err;
105
106
case HIDPCONNDEL:
107
if (!capable(CAP_NET_ADMIN))
108
return -EACCES;
109
110
if (copy_from_user(&cd, argp, sizeof(cd)))
111
return -EFAULT;
112
113
return hidp_del_connection(&cd);
114
115
case HIDPGETCONNLIST:
116
if (copy_from_user(&cl, argp, sizeof(cl)))
117
return -EFAULT;
118
119
if (cl.cnum <= 0)
120
return -EINVAL;
121
122
err = hidp_get_connlist(&cl);
123
if (!err && copy_to_user(argp, &cl, sizeof(cl)))
124
return -EFAULT;
125
126
return err;
127
128
case HIDPGETCONNINFO:
129
if (copy_from_user(&ci, argp, sizeof(ci)))
130
return -EFAULT;
131
132
err = hidp_get_conninfo(&ci);
133
if (!err && copy_to_user(argp, &ci, sizeof(ci)))
134
return -EFAULT;
135
136
return err;
137
}
138
139
return -EINVAL;
140
}
141
142
#ifdef CONFIG_COMPAT
143
struct compat_hidp_connadd_req {
144
int ctrl_sock; /* Connected control socket */
145
int intr_sock; /* Connected interrupt socket */
146
__u16 parser;
147
__u16 rd_size;
148
compat_uptr_t rd_data;
149
__u8 country;
150
__u8 subclass;
151
__u16 vendor;
152
__u16 product;
153
__u16 version;
154
__u32 flags;
155
__u32 idle_to;
156
char name[128];
157
};
158
159
static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
160
{
161
if (cmd == HIDPGETCONNLIST) {
162
struct hidp_connlist_req cl;
163
uint32_t uci;
164
int err;
165
166
if (get_user(cl.cnum, (uint32_t __user *) arg) ||
167
get_user(uci, (u32 __user *) (arg + 4)))
168
return -EFAULT;
169
170
cl.ci = compat_ptr(uci);
171
172
if (cl.cnum <= 0)
173
return -EINVAL;
174
175
err = hidp_get_connlist(&cl);
176
177
if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
178
err = -EFAULT;
179
180
return err;
181
} else if (cmd == HIDPCONNADD) {
182
struct compat_hidp_connadd_req ca;
183
struct hidp_connadd_req __user *uca;
184
185
uca = compat_alloc_user_space(sizeof(*uca));
186
187
if (copy_from_user(&ca, (void __user *) arg, sizeof(ca)))
188
return -EFAULT;
189
190
if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
191
put_user(ca.intr_sock, &uca->intr_sock) ||
192
put_user(ca.parser, &uca->parser) ||
193
put_user(ca.rd_size, &uca->rd_size) ||
194
put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
195
put_user(ca.country, &uca->country) ||
196
put_user(ca.subclass, &uca->subclass) ||
197
put_user(ca.vendor, &uca->vendor) ||
198
put_user(ca.product, &uca->product) ||
199
put_user(ca.version, &uca->version) ||
200
put_user(ca.flags, &uca->flags) ||
201
put_user(ca.idle_to, &uca->idle_to) ||
202
copy_to_user(&uca->name[0], &ca.name[0], 128))
203
return -EFAULT;
204
205
arg = (unsigned long) uca;
206
207
/* Fall through. We don't actually write back any _changes_
208
to the structure anyway, so there's no need to copy back
209
into the original compat version */
210
}
211
212
return hidp_sock_ioctl(sock, cmd, arg);
213
}
214
#endif
215
216
static const struct proto_ops hidp_sock_ops = {
217
.family = PF_BLUETOOTH,
218
.owner = THIS_MODULE,
219
.release = hidp_sock_release,
220
.ioctl = hidp_sock_ioctl,
221
#ifdef CONFIG_COMPAT
222
.compat_ioctl = hidp_sock_compat_ioctl,
223
#endif
224
.bind = sock_no_bind,
225
.getname = sock_no_getname,
226
.sendmsg = sock_no_sendmsg,
227
.recvmsg = sock_no_recvmsg,
228
.poll = sock_no_poll,
229
.listen = sock_no_listen,
230
.shutdown = sock_no_shutdown,
231
.setsockopt = sock_no_setsockopt,
232
.getsockopt = sock_no_getsockopt,
233
.connect = sock_no_connect,
234
.socketpair = sock_no_socketpair,
235
.accept = sock_no_accept,
236
.mmap = sock_no_mmap
237
};
238
239
static struct proto hidp_proto = {
240
.name = "HIDP",
241
.owner = THIS_MODULE,
242
.obj_size = sizeof(struct bt_sock)
243
};
244
245
static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
246
int kern)
247
{
248
struct sock *sk;
249
250
BT_DBG("sock %p", sock);
251
252
if (sock->type != SOCK_RAW)
253
return -ESOCKTNOSUPPORT;
254
255
sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto);
256
if (!sk)
257
return -ENOMEM;
258
259
sock_init_data(sock, sk);
260
261
sock->ops = &hidp_sock_ops;
262
263
sock->state = SS_UNCONNECTED;
264
265
sock_reset_flag(sk, SOCK_ZAPPED);
266
267
sk->sk_protocol = protocol;
268
sk->sk_state = BT_OPEN;
269
270
return 0;
271
}
272
273
static const struct net_proto_family hidp_sock_family_ops = {
274
.family = PF_BLUETOOTH,
275
.owner = THIS_MODULE,
276
.create = hidp_sock_create
277
};
278
279
int __init hidp_init_sockets(void)
280
{
281
int err;
282
283
err = proto_register(&hidp_proto, 0);
284
if (err < 0)
285
return err;
286
287
err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
288
if (err < 0)
289
goto error;
290
291
return 0;
292
293
error:
294
BT_ERR("Can't register HIDP socket");
295
proto_unregister(&hidp_proto);
296
return err;
297
}
298
299
void __exit hidp_cleanup_sockets(void)
300
{
301
if (bt_sock_unregister(BTPROTO_HIDP) < 0)
302
BT_ERR("Can't unregister HIDP socket");
303
304
proto_unregister(&hidp_proto);
305
}
306
307