Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/bluetooth/bnep/sock.c
26285 views
1
/*
2
BNEP implementation for Linux Bluetooth stack (BlueZ).
3
Copyright (C) 2001-2002 Inventel Systemes
4
Written 2001-2002 by
5
David Libault <[email protected]>
6
7
Copyright (C) 2002 Maxim Krasnyansky <[email protected]>
8
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License version 2 as
11
published by the Free Software Foundation;
12
13
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
17
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
22
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
24
SOFTWARE IS DISCLAIMED.
25
*/
26
27
#include <linux/compat.h>
28
#include <linux/export.h>
29
#include <linux/file.h>
30
31
#include "bnep.h"
32
33
static struct bt_sock_list bnep_sk_list = {
34
.lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
35
};
36
37
static int bnep_sock_release(struct socket *sock)
38
{
39
struct sock *sk = sock->sk;
40
41
BT_DBG("sock %p sk %p", sock, sk);
42
43
if (!sk)
44
return 0;
45
46
bt_sock_unlink(&bnep_sk_list, sk);
47
48
sock_orphan(sk);
49
sock_put(sk);
50
return 0;
51
}
52
53
static int do_bnep_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
54
{
55
struct bnep_connlist_req cl;
56
struct bnep_connadd_req ca;
57
struct bnep_conndel_req cd;
58
struct bnep_conninfo ci;
59
struct socket *nsock;
60
__u32 supp_feat = BIT(BNEP_SETUP_RESPONSE);
61
int err;
62
63
BT_DBG("cmd %x arg %p", cmd, argp);
64
65
switch (cmd) {
66
case BNEPCONNADD:
67
if (!capable(CAP_NET_ADMIN))
68
return -EPERM;
69
70
if (copy_from_user(&ca, argp, sizeof(ca)))
71
return -EFAULT;
72
73
nsock = sockfd_lookup(ca.sock, &err);
74
if (!nsock)
75
return err;
76
77
if (nsock->sk->sk_state != BT_CONNECTED) {
78
sockfd_put(nsock);
79
return -EBADFD;
80
}
81
ca.device[sizeof(ca.device)-1] = 0;
82
83
err = bnep_add_connection(&ca, nsock);
84
if (!err) {
85
if (copy_to_user(argp, &ca, sizeof(ca)))
86
err = -EFAULT;
87
} else
88
sockfd_put(nsock);
89
90
return err;
91
92
case BNEPCONNDEL:
93
if (!capable(CAP_NET_ADMIN))
94
return -EPERM;
95
96
if (copy_from_user(&cd, argp, sizeof(cd)))
97
return -EFAULT;
98
99
return bnep_del_connection(&cd);
100
101
case BNEPGETCONNLIST:
102
if (copy_from_user(&cl, argp, sizeof(cl)))
103
return -EFAULT;
104
105
if (cl.cnum <= 0)
106
return -EINVAL;
107
108
err = bnep_get_connlist(&cl);
109
if (!err && copy_to_user(argp, &cl, sizeof(cl)))
110
return -EFAULT;
111
112
return err;
113
114
case BNEPGETCONNINFO:
115
if (copy_from_user(&ci, argp, sizeof(ci)))
116
return -EFAULT;
117
118
err = bnep_get_conninfo(&ci);
119
if (!err && copy_to_user(argp, &ci, sizeof(ci)))
120
return -EFAULT;
121
122
return err;
123
124
case BNEPGETSUPPFEAT:
125
if (copy_to_user(argp, &supp_feat, sizeof(supp_feat)))
126
return -EFAULT;
127
128
return 0;
129
130
default:
131
return -EINVAL;
132
}
133
134
return 0;
135
}
136
137
static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
138
{
139
return do_bnep_sock_ioctl(sock, cmd, (void __user *)arg);
140
}
141
142
#ifdef CONFIG_COMPAT
143
static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
144
{
145
void __user *argp = compat_ptr(arg);
146
if (cmd == BNEPGETCONNLIST) {
147
struct bnep_connlist_req cl;
148
unsigned __user *p = argp;
149
u32 uci;
150
int err;
151
152
if (get_user(cl.cnum, p) || get_user(uci, p + 1))
153
return -EFAULT;
154
155
cl.ci = compat_ptr(uci);
156
157
if (cl.cnum <= 0)
158
return -EINVAL;
159
160
err = bnep_get_connlist(&cl);
161
162
if (!err && put_user(cl.cnum, p))
163
err = -EFAULT;
164
165
return err;
166
}
167
168
return do_bnep_sock_ioctl(sock, cmd, argp);
169
}
170
#endif
171
172
static const struct proto_ops bnep_sock_ops = {
173
.family = PF_BLUETOOTH,
174
.owner = THIS_MODULE,
175
.release = bnep_sock_release,
176
.ioctl = bnep_sock_ioctl,
177
#ifdef CONFIG_COMPAT
178
.compat_ioctl = bnep_sock_compat_ioctl,
179
#endif
180
.bind = sock_no_bind,
181
.getname = sock_no_getname,
182
.sendmsg = sock_no_sendmsg,
183
.recvmsg = sock_no_recvmsg,
184
.listen = sock_no_listen,
185
.shutdown = sock_no_shutdown,
186
.connect = sock_no_connect,
187
.socketpair = sock_no_socketpair,
188
.accept = sock_no_accept,
189
.mmap = sock_no_mmap
190
};
191
192
static struct proto bnep_proto = {
193
.name = "BNEP",
194
.owner = THIS_MODULE,
195
.obj_size = sizeof(struct bt_sock)
196
};
197
198
static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
199
int kern)
200
{
201
struct sock *sk;
202
203
BT_DBG("sock %p", sock);
204
205
if (sock->type != SOCK_RAW)
206
return -ESOCKTNOSUPPORT;
207
208
sk = bt_sock_alloc(net, sock, &bnep_proto, protocol, GFP_ATOMIC, kern);
209
if (!sk)
210
return -ENOMEM;
211
212
sock->ops = &bnep_sock_ops;
213
sock->state = SS_UNCONNECTED;
214
215
bt_sock_link(&bnep_sk_list, sk);
216
return 0;
217
}
218
219
static const struct net_proto_family bnep_sock_family_ops = {
220
.family = PF_BLUETOOTH,
221
.owner = THIS_MODULE,
222
.create = bnep_sock_create
223
};
224
225
int __init bnep_sock_init(void)
226
{
227
int err;
228
229
err = proto_register(&bnep_proto, 0);
230
if (err < 0)
231
return err;
232
233
err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
234
if (err < 0) {
235
BT_ERR("Can't register BNEP socket");
236
goto error;
237
}
238
239
err = bt_procfs_init(&init_net, "bnep", &bnep_sk_list, NULL);
240
if (err < 0) {
241
BT_ERR("Failed to create BNEP proc file");
242
bt_sock_unregister(BTPROTO_BNEP);
243
goto error;
244
}
245
246
BT_INFO("BNEP socket layer initialized");
247
248
return 0;
249
250
error:
251
proto_unregister(&bnep_proto);
252
return err;
253
}
254
255
void __exit bnep_sock_cleanup(void)
256
{
257
bt_procfs_cleanup(&init_net, "bnep");
258
bt_sock_unregister(BTPROTO_BNEP);
259
proto_unregister(&bnep_proto);
260
}
261
262