~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/bluetooth/hidp/sock.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.12 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.55 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.136 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.191 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp