1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <linux/export.h>
28#include <linux/file.h>
29
30#include "bnep.h"
31
32static struct bt_sock_list bnep_sk_list = {
33 .lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
34};
35
36static int bnep_sock_release(struct socket *sock)
37{
38 struct sock *sk = sock->sk;
39
40 BT_DBG("sock %p sk %p", sock, sk);
41
42 if (!sk)
43 return 0;
44
45 bt_sock_unlink(&bnep_sk_list, sk);
46
47 sock_orphan(sk);
48 sock_put(sk);
49 return 0;
50}
51
52static int do_bnep_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
53{
54 struct bnep_connlist_req cl;
55 struct bnep_connadd_req ca;
56 struct bnep_conndel_req cd;
57 struct bnep_conninfo ci;
58 struct socket *nsock;
59 __u32 supp_feat = BIT(BNEP_SETUP_RESPONSE);
60 int err;
61
62 BT_DBG("cmd %x arg %p", cmd, argp);
63
64 switch (cmd) {
65 case BNEPCONNADD:
66 if (!capable(CAP_NET_ADMIN))
67 return -EPERM;
68
69 if (copy_from_user(&ca, argp, sizeof(ca)))
70 return -EFAULT;
71
72 nsock = sockfd_lookup(ca.sock, &err);
73 if (!nsock)
74 return err;
75
76 if (nsock->sk->sk_state != BT_CONNECTED) {
77 sockfd_put(nsock);
78 return -EBADFD;
79 }
80 ca.device[sizeof(ca.device)-1] = 0;
81
82 err = bnep_add_connection(&ca, nsock);
83 if (!err) {
84 if (copy_to_user(argp, &ca, sizeof(ca)))
85 err = -EFAULT;
86 } else
87 sockfd_put(nsock);
88
89 return err;
90
91 case BNEPCONNDEL:
92 if (!capable(CAP_NET_ADMIN))
93 return -EPERM;
94
95 if (copy_from_user(&cd, argp, sizeof(cd)))
96 return -EFAULT;
97
98 return bnep_del_connection(&cd);
99
100 case BNEPGETCONNLIST:
101 if (copy_from_user(&cl, argp, sizeof(cl)))
102 return -EFAULT;
103
104 if (cl.cnum <= 0)
105 return -EINVAL;
106
107 err = bnep_get_connlist(&cl);
108 if (!err && copy_to_user(argp, &cl, sizeof(cl)))
109 return -EFAULT;
110
111 return err;
112
113 case BNEPGETCONNINFO:
114 if (copy_from_user(&ci, argp, sizeof(ci)))
115 return -EFAULT;
116
117 err = bnep_get_conninfo(&ci);
118 if (!err && copy_to_user(argp, &ci, sizeof(ci)))
119 return -EFAULT;
120
121 return err;
122
123 case BNEPGETSUPPFEAT:
124 if (copy_to_user(argp, &supp_feat, sizeof(supp_feat)))
125 return -EFAULT;
126
127 return 0;
128
129 default:
130 return -EINVAL;
131 }
132
133 return 0;
134}
135
136static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
137{
138 return do_bnep_sock_ioctl(sock, cmd, (void __user *)arg);
139}
140
141#ifdef CONFIG_COMPAT
142static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
143{
144 void __user *argp = compat_ptr(arg);
145 if (cmd == BNEPGETCONNLIST) {
146 struct bnep_connlist_req cl;
147 unsigned __user *p = argp;
148 u32 uci;
149 int err;
150
151 if (get_user(cl.cnum, p) || get_user(uci, p + 1))
152 return -EFAULT;
153
154 cl.ci = compat_ptr(uci);
155
156 if (cl.cnum <= 0)
157 return -EINVAL;
158
159 err = bnep_get_connlist(&cl);
160
161 if (!err && put_user(cl.cnum, p))
162 err = -EFAULT;
163
164 return err;
165 }
166
167 return do_bnep_sock_ioctl(sock, cmd, argp);
168}
169#endif
170
171static const struct proto_ops bnep_sock_ops = {
172 .family = PF_BLUETOOTH,
173 .owner = THIS_MODULE,
174 .release = bnep_sock_release,
175 .ioctl = bnep_sock_ioctl,
176#ifdef CONFIG_COMPAT
177 .compat_ioctl = bnep_sock_compat_ioctl,
178#endif
179 .bind = sock_no_bind,
180 .getname = sock_no_getname,
181 .sendmsg = sock_no_sendmsg,
182 .recvmsg = sock_no_recvmsg,
183 .listen = sock_no_listen,
184 .shutdown = sock_no_shutdown,
185 .connect = sock_no_connect,
186 .socketpair = sock_no_socketpair,
187 .accept = sock_no_accept,
188 .mmap = sock_no_mmap
189};
190
191static struct proto bnep_proto = {
192 .name = "BNEP",
193 .owner = THIS_MODULE,
194 .obj_size = sizeof(struct bt_sock)
195};
196
197static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
198 int kern)
199{
200 struct sock *sk;
201
202 BT_DBG("sock %p", sock);
203
204 if (sock->type != SOCK_RAW)
205 return -ESOCKTNOSUPPORT;
206
207 sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, kern);
208 if (!sk)
209 return -ENOMEM;
210
211 sock_init_data(sock, sk);
212
213 sock->ops = &bnep_sock_ops;
214
215 sock->state = SS_UNCONNECTED;
216
217 sock_reset_flag(sk, SOCK_ZAPPED);
218
219 sk->sk_protocol = protocol;
220 sk->sk_state = BT_OPEN;
221
222 bt_sock_link(&bnep_sk_list, sk);
223 return 0;
224}
225
226static const struct net_proto_family bnep_sock_family_ops = {
227 .family = PF_BLUETOOTH,
228 .owner = THIS_MODULE,
229 .create = bnep_sock_create
230};
231
232int __init bnep_sock_init(void)
233{
234 int err;
235
236 err = proto_register(&bnep_proto, 0);
237 if (err < 0)
238 return err;
239
240 err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
241 if (err < 0) {
242 BT_ERR("Can't register BNEP socket");
243 goto error;
244 }
245
246 err = bt_procfs_init(&init_net, "bnep", &bnep_sk_list, NULL);
247 if (err < 0) {
248 BT_ERR("Failed to create BNEP proc file");
249 bt_sock_unregister(BTPROTO_BNEP);
250 goto error;
251 }
252
253 BT_INFO("BNEP socket layer initialized");
254
255 return 0;
256
257error:
258 proto_unregister(&bnep_proto);
259 return err;
260}
261
262void __exit bnep_sock_cleanup(void)
263{
264 bt_procfs_cleanup(&init_net, "bnep");
265 bt_sock_unregister(BTPROTO_BNEP);
266 proto_unregister(&bnep_proto);
267}
268