Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sock.c
Go to the documentation of this file.
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/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 hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
50 {
51  void __user *argp = (void __user *) arg;
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 %lx", cmd, arg);
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 
80  if (csock->sk->sk_state != BT_CONNECTED ||
81  isock->sk->sk_state != BT_CONNECTED) {
82  sockfd_put(csock);
83  sockfd_put(isock);
84  return -EBADFD;
85  }
86 
87  err = hidp_add_connection(&ca, csock, isock);
88  if (!err) {
89  if (copy_to_user(argp, &ca, sizeof(ca)))
90  err = -EFAULT;
91  } else {
92  sockfd_put(csock);
93  sockfd_put(isock);
94  }
95 
96  return err;
97 
98  case HIDPCONNDEL:
99  if (!capable(CAP_NET_ADMIN))
100  return -EPERM;
101 
102  if (copy_from_user(&cd, argp, sizeof(cd)))
103  return -EFAULT;
104 
105  return hidp_del_connection(&cd);
106 
107  case HIDPGETCONNLIST:
108  if (copy_from_user(&cl, argp, sizeof(cl)))
109  return -EFAULT;
110 
111  if (cl.cnum <= 0)
112  return -EINVAL;
113 
114  err = hidp_get_connlist(&cl);
115  if (!err && copy_to_user(argp, &cl, sizeof(cl)))
116  return -EFAULT;
117 
118  return err;
119 
120  case HIDPGETCONNINFO:
121  if (copy_from_user(&ci, argp, sizeof(ci)))
122  return -EFAULT;
123 
124  err = hidp_get_conninfo(&ci);
125  if (!err && copy_to_user(argp, &ci, sizeof(ci)))
126  return -EFAULT;
127 
128  return err;
129  }
130 
131  return -EINVAL;
132 }
133 
134 #ifdef CONFIG_COMPAT
135 struct compat_hidp_connadd_req {
136  int ctrl_sock; /* Connected control socket */
137  int intr_sock; /* Connected interrupt socket */
138  __u16 parser;
139  __u16 rd_size;
141  __u8 country;
142  __u8 subclass;
143  __u16 vendor;
144  __u16 product;
145  __u16 version;
146  __u32 flags;
147  __u32 idle_to;
148  char name[128];
149 };
150 
151 static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
152 {
153  if (cmd == HIDPGETCONNLIST) {
154  struct hidp_connlist_req cl;
155  u32 uci;
156  int err;
157 
158  if (get_user(cl.cnum, (u32 __user *) arg) ||
159  get_user(uci, (u32 __user *) (arg + 4)))
160  return -EFAULT;
161 
162  cl.ci = compat_ptr(uci);
163 
164  if (cl.cnum <= 0)
165  return -EINVAL;
166 
167  err = hidp_get_connlist(&cl);
168 
169  if (!err && put_user(cl.cnum, (u32 __user *) arg))
170  err = -EFAULT;
171 
172  return err;
173  } else if (cmd == HIDPCONNADD) {
174  struct compat_hidp_connadd_req ca;
175  struct hidp_connadd_req __user *uca;
176 
177  uca = compat_alloc_user_space(sizeof(*uca));
178 
179  if (copy_from_user(&ca, (void __user *) arg, sizeof(ca)))
180  return -EFAULT;
181 
182  if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
183  put_user(ca.intr_sock, &uca->intr_sock) ||
184  put_user(ca.parser, &uca->parser) ||
185  put_user(ca.rd_size, &uca->rd_size) ||
186  put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
187  put_user(ca.country, &uca->country) ||
188  put_user(ca.subclass, &uca->subclass) ||
189  put_user(ca.vendor, &uca->vendor) ||
190  put_user(ca.product, &uca->product) ||
191  put_user(ca.version, &uca->version) ||
192  put_user(ca.flags, &uca->flags) ||
193  put_user(ca.idle_to, &uca->idle_to) ||
194  copy_to_user(&uca->name[0], &ca.name[0], 128))
195  return -EFAULT;
196 
197  arg = (unsigned long) uca;
198 
199  /* Fall through. We don't actually write back any _changes_
200  to the structure anyway, so there's no need to copy back
201  into the original compat version */
202  }
203 
204  return hidp_sock_ioctl(sock, cmd, arg);
205 }
206 #endif
207 
208 static const struct proto_ops hidp_sock_ops = {
209  .family = PF_BLUETOOTH,
210  .owner = THIS_MODULE,
211  .release = hidp_sock_release,
212  .ioctl = hidp_sock_ioctl,
213 #ifdef CONFIG_COMPAT
214  .compat_ioctl = hidp_sock_compat_ioctl,
215 #endif
216  .bind = sock_no_bind,
217  .getname = sock_no_getname,
218  .sendmsg = sock_no_sendmsg,
219  .recvmsg = sock_no_recvmsg,
220  .poll = sock_no_poll,
221  .listen = sock_no_listen,
222  .shutdown = sock_no_shutdown,
223  .setsockopt = sock_no_setsockopt,
224  .getsockopt = sock_no_getsockopt,
225  .connect = sock_no_connect,
226  .socketpair = sock_no_socketpair,
227  .accept = sock_no_accept,
228  .mmap = sock_no_mmap
229 };
230 
231 static struct proto hidp_proto = {
232  .name = "HIDP",
233  .owner = THIS_MODULE,
234  .obj_size = sizeof(struct bt_sock)
235 };
236 
237 static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
238  int kern)
239 {
240  struct sock *sk;
241 
242  BT_DBG("sock %p", sock);
243 
244  if (sock->type != SOCK_RAW)
245  return -ESOCKTNOSUPPORT;
246 
247  sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto);
248  if (!sk)
249  return -ENOMEM;
250 
251  sock_init_data(sock, sk);
252 
253  sock->ops = &hidp_sock_ops;
254 
255  sock->state = SS_UNCONNECTED;
256 
257  sock_reset_flag(sk, SOCK_ZAPPED);
258 
259  sk->sk_protocol = protocol;
260  sk->sk_state = BT_OPEN;
261 
262  bt_sock_link(&hidp_sk_list, sk);
263 
264  return 0;
265 }
266 
267 static const struct net_proto_family hidp_sock_family_ops = {
268  .family = PF_BLUETOOTH,
269  .owner = THIS_MODULE,
270  .create = hidp_sock_create
271 };
272 
274 {
275  int err;
276 
277  err = proto_register(&hidp_proto, 0);
278  if (err < 0)
279  return err;
280 
281  err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
282  if (err < 0) {
283  BT_ERR("Can't register HIDP socket");
284  goto error;
285  }
286 
287  err = bt_procfs_init(THIS_MODULE, &init_net, "hidp", &hidp_sk_list, NULL);
288  if (err < 0) {
289  BT_ERR("Failed to create HIDP proc file");
291  goto error;
292  }
293 
294  BT_INFO("HIDP socket layer initialized");
295 
296  return 0;
297 
298 error:
299  BT_ERR("Can't register HIDP socket");
300  proto_unregister(&hidp_proto);
301  return err;
302 }
303 
305 {
306  bt_procfs_cleanup(&init_net, "hidp");
308  BT_ERR("Can't unregister HIDP socket");
309 
310  proto_unregister(&hidp_proto);
311 }