GNU Linux-libre 5.4.207-gnu1
[releases.git] / net / bluetooth / bnep / sock.c
1 /*
2    BNEP implementation for Linux Bluetooth stack (BlueZ).
3    Copyright (C) 2001-2002 Inventel Systemes
4    Written 2001-2002 by
5         David Libault  <david.libault@inventel.fr>
6
7    Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
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/export.h>
28 #include <linux/file.h>
29
30 #include "bnep.h"
31
32 static struct bt_sock_list bnep_sk_list = {
33         .lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
34 };
35
36 static 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
52 static 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
136 static 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
142 static 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
171 static 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         .setsockopt     = sock_no_setsockopt,
186         .getsockopt     = sock_no_getsockopt,
187         .connect        = sock_no_connect,
188         .socketpair     = sock_no_socketpair,
189         .accept         = sock_no_accept,
190         .mmap           = sock_no_mmap
191 };
192
193 static struct proto bnep_proto = {
194         .name           = "BNEP",
195         .owner          = THIS_MODULE,
196         .obj_size       = sizeof(struct bt_sock)
197 };
198
199 static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
200                             int kern)
201 {
202         struct sock *sk;
203
204         BT_DBG("sock %p", sock);
205
206         if (sock->type != SOCK_RAW)
207                 return -ESOCKTNOSUPPORT;
208
209         sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, kern);
210         if (!sk)
211                 return -ENOMEM;
212
213         sock_init_data(sock, sk);
214
215         sock->ops = &bnep_sock_ops;
216
217         sock->state = SS_UNCONNECTED;
218
219         sock_reset_flag(sk, SOCK_ZAPPED);
220
221         sk->sk_protocol = protocol;
222         sk->sk_state    = BT_OPEN;
223
224         bt_sock_link(&bnep_sk_list, sk);
225         return 0;
226 }
227
228 static const struct net_proto_family bnep_sock_family_ops = {
229         .family = PF_BLUETOOTH,
230         .owner  = THIS_MODULE,
231         .create = bnep_sock_create
232 };
233
234 int __init bnep_sock_init(void)
235 {
236         int err;
237
238         err = proto_register(&bnep_proto, 0);
239         if (err < 0)
240                 return err;
241
242         err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
243         if (err < 0) {
244                 BT_ERR("Can't register BNEP socket");
245                 goto error;
246         }
247
248         err = bt_procfs_init(&init_net, "bnep", &bnep_sk_list, NULL);
249         if (err < 0) {
250                 BT_ERR("Failed to create BNEP proc file");
251                 bt_sock_unregister(BTPROTO_BNEP);
252                 goto error;
253         }
254
255         BT_INFO("BNEP socket layer initialized");
256
257         return 0;
258
259 error:
260         proto_unregister(&bnep_proto);
261         return err;
262 }
263
264 void __exit bnep_sock_cleanup(void)
265 {
266         bt_procfs_cleanup(&init_net, "bnep");
267         bt_sock_unregister(BTPROTO_BNEP);
268         proto_unregister(&bnep_proto);
269 }