Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/bluetooth/hidp/sock.c
29271 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/compat.h>
24
#include <linux/export.h>
25
#include <linux/file.h>
26
27
#include "hidp.h"
28
29
static struct bt_sock_list hidp_sk_list = {
30
.lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
31
};
32
33
static int hidp_sock_release(struct socket *sock)
34
{
35
struct sock *sk = sock->sk;
36
37
BT_DBG("sock %p sk %p", sock, sk);
38
39
if (!sk)
40
return 0;
41
42
bt_sock_unlink(&hidp_sk_list, sk);
43
44
sock_orphan(sk);
45
sock_put(sk);
46
47
return 0;
48
}
49
50
static int do_hidp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
51
{
52
struct hidp_connadd_req ca;
53
struct hidp_conndel_req cd;
54
struct hidp_connlist_req cl;
55
struct hidp_conninfo ci;
56
struct socket *csock;
57
struct socket *isock;
58
int err;
59
60
BT_DBG("cmd %x arg %p", cmd, argp);
61
62
switch (cmd) {
63
case HIDPCONNADD:
64
if (!capable(CAP_NET_ADMIN))
65
return -EPERM;
66
67
if (copy_from_user(&ca, argp, sizeof(ca)))
68
return -EFAULT;
69
70
csock = sockfd_lookup(ca.ctrl_sock, &err);
71
if (!csock)
72
return err;
73
74
isock = sockfd_lookup(ca.intr_sock, &err);
75
if (!isock) {
76
sockfd_put(csock);
77
return err;
78
}
79
ca.name[sizeof(ca.name)-1] = 0;
80
81
err = hidp_connection_add(&ca, csock, isock);
82
if (!err && copy_to_user(argp, &ca, sizeof(ca)))
83
err = -EFAULT;
84
85
sockfd_put(csock);
86
sockfd_put(isock);
87
88
return err;
89
90
case HIDPCONNDEL:
91
if (!capable(CAP_NET_ADMIN))
92
return -EPERM;
93
94
if (copy_from_user(&cd, argp, sizeof(cd)))
95
return -EFAULT;
96
97
return hidp_connection_del(&cd);
98
99
case HIDPGETCONNLIST:
100
if (copy_from_user(&cl, argp, sizeof(cl)))
101
return -EFAULT;
102
103
if (cl.cnum <= 0)
104
return -EINVAL;
105
106
err = hidp_get_connlist(&cl);
107
if (!err && copy_to_user(argp, &cl, sizeof(cl)))
108
return -EFAULT;
109
110
return err;
111
112
case HIDPGETCONNINFO:
113
if (copy_from_user(&ci, argp, sizeof(ci)))
114
return -EFAULT;
115
116
err = hidp_get_conninfo(&ci);
117
if (!err && copy_to_user(argp, &ci, sizeof(ci)))
118
return -EFAULT;
119
120
return err;
121
}
122
123
return -EINVAL;
124
}
125
126
static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
127
{
128
return do_hidp_sock_ioctl(sock, cmd, (void __user *)arg);
129
}
130
131
#ifdef CONFIG_COMPAT
132
struct compat_hidp_connadd_req {
133
int ctrl_sock; /* Connected control socket */
134
int intr_sock; /* Connected interrupt socket */
135
__u16 parser;
136
__u16 rd_size;
137
compat_uptr_t rd_data;
138
__u8 country;
139
__u8 subclass;
140
__u16 vendor;
141
__u16 product;
142
__u16 version;
143
__u32 flags;
144
__u32 idle_to;
145
char name[128];
146
};
147
148
static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
149
{
150
void __user *argp = compat_ptr(arg);
151
int err;
152
153
if (cmd == HIDPGETCONNLIST) {
154
struct hidp_connlist_req cl;
155
u32 __user *p = argp;
156
u32 uci;
157
158
if (get_user(cl.cnum, p) || get_user(uci, p + 1))
159
return -EFAULT;
160
161
cl.ci = compat_ptr(uci);
162
163
if (cl.cnum <= 0)
164
return -EINVAL;
165
166
err = hidp_get_connlist(&cl);
167
168
if (!err && put_user(cl.cnum, p))
169
err = -EFAULT;
170
171
return err;
172
} else if (cmd == HIDPCONNADD) {
173
struct compat_hidp_connadd_req ca32;
174
struct hidp_connadd_req ca;
175
struct socket *csock;
176
struct socket *isock;
177
178
if (!capable(CAP_NET_ADMIN))
179
return -EPERM;
180
181
if (copy_from_user(&ca32, (void __user *) arg, sizeof(ca32)))
182
return -EFAULT;
183
184
ca.ctrl_sock = ca32.ctrl_sock;
185
ca.intr_sock = ca32.intr_sock;
186
ca.parser = ca32.parser;
187
ca.rd_size = ca32.rd_size;
188
ca.rd_data = compat_ptr(ca32.rd_data);
189
ca.country = ca32.country;
190
ca.subclass = ca32.subclass;
191
ca.vendor = ca32.vendor;
192
ca.product = ca32.product;
193
ca.version = ca32.version;
194
ca.flags = ca32.flags;
195
ca.idle_to = ca32.idle_to;
196
ca32.name[sizeof(ca32.name) - 1] = '\0';
197
memcpy(ca.name, ca32.name, 128);
198
199
csock = sockfd_lookup(ca.ctrl_sock, &err);
200
if (!csock)
201
return err;
202
203
isock = sockfd_lookup(ca.intr_sock, &err);
204
if (!isock) {
205
sockfd_put(csock);
206
return err;
207
}
208
209
err = hidp_connection_add(&ca, csock, isock);
210
if (!err && copy_to_user(argp, &ca32, sizeof(ca32)))
211
err = -EFAULT;
212
213
sockfd_put(csock);
214
sockfd_put(isock);
215
216
return err;
217
}
218
219
return hidp_sock_ioctl(sock, cmd, arg);
220
}
221
#endif
222
223
static const struct proto_ops hidp_sock_ops = {
224
.family = PF_BLUETOOTH,
225
.owner = THIS_MODULE,
226
.release = hidp_sock_release,
227
.ioctl = hidp_sock_ioctl,
228
#ifdef CONFIG_COMPAT
229
.compat_ioctl = hidp_sock_compat_ioctl,
230
#endif
231
.bind = sock_no_bind,
232
.getname = sock_no_getname,
233
.sendmsg = sock_no_sendmsg,
234
.recvmsg = sock_no_recvmsg,
235
.listen = sock_no_listen,
236
.shutdown = sock_no_shutdown,
237
.connect = sock_no_connect,
238
.socketpair = sock_no_socketpair,
239
.accept = sock_no_accept,
240
.mmap = sock_no_mmap
241
};
242
243
static struct proto hidp_proto = {
244
.name = "HIDP",
245
.owner = THIS_MODULE,
246
.obj_size = sizeof(struct bt_sock)
247
};
248
249
static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
250
int kern)
251
{
252
struct sock *sk;
253
254
BT_DBG("sock %p", sock);
255
256
if (sock->type != SOCK_RAW)
257
return -ESOCKTNOSUPPORT;
258
259
sk = bt_sock_alloc(net, sock, &hidp_proto, protocol, GFP_ATOMIC, kern);
260
if (!sk)
261
return -ENOMEM;
262
263
sock->ops = &hidp_sock_ops;
264
sock->state = SS_UNCONNECTED;
265
266
bt_sock_link(&hidp_sk_list, sk);
267
268
return 0;
269
}
270
271
static const struct net_proto_family hidp_sock_family_ops = {
272
.family = PF_BLUETOOTH,
273
.owner = THIS_MODULE,
274
.create = hidp_sock_create
275
};
276
277
int __init hidp_init_sockets(void)
278
{
279
int err;
280
281
err = proto_register(&hidp_proto, 0);
282
if (err < 0)
283
return err;
284
285
err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
286
if (err < 0) {
287
BT_ERR("Can't register HIDP socket");
288
goto error;
289
}
290
291
err = bt_procfs_init(&init_net, "hidp", &hidp_sk_list, NULL);
292
if (err < 0) {
293
BT_ERR("Failed to create HIDP proc file");
294
bt_sock_unregister(BTPROTO_HIDP);
295
goto error;
296
}
297
298
BT_INFO("HIDP socket layer initialized");
299
300
return 0;
301
302
error:
303
proto_unregister(&hidp_proto);
304
return err;
305
}
306
307
void __exit hidp_cleanup_sockets(void)
308
{
309
bt_procfs_cleanup(&init_net, "hidp");
310
bt_sock_unregister(BTPROTO_HIDP);
311
proto_unregister(&hidp_proto);
312
}
313
314