Back to home page

OSCL-LXR

 
 

    


0001 /*
0002    HIDP implementation for Linux Bluetooth stack (BlueZ).
0003    Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
0004 
0005    This program is free software; you can redistribute it and/or modify
0006    it under the terms of the GNU General Public License version 2 as
0007    published by the Free Software Foundation;
0008 
0009    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0010    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0011    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
0012    IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
0013    CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
0014    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0015    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0016    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0017 
0018    ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
0019    COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
0020    SOFTWARE IS DISCLAIMED.
0021 */
0022 
0023 #include <linux/compat.h>
0024 #include <linux/export.h>
0025 #include <linux/file.h>
0026 
0027 #include "hidp.h"
0028 
0029 static struct bt_sock_list hidp_sk_list = {
0030     .lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
0031 };
0032 
0033 static int hidp_sock_release(struct socket *sock)
0034 {
0035     struct sock *sk = sock->sk;
0036 
0037     BT_DBG("sock %p sk %p", sock, sk);
0038 
0039     if (!sk)
0040         return 0;
0041 
0042     bt_sock_unlink(&hidp_sk_list, sk);
0043 
0044     sock_orphan(sk);
0045     sock_put(sk);
0046 
0047     return 0;
0048 }
0049 
0050 static int do_hidp_sock_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
0051 {
0052     struct hidp_connadd_req ca;
0053     struct hidp_conndel_req cd;
0054     struct hidp_connlist_req cl;
0055     struct hidp_conninfo ci;
0056     struct socket *csock;
0057     struct socket *isock;
0058     int err;
0059 
0060     BT_DBG("cmd %x arg %p", cmd, argp);
0061 
0062     switch (cmd) {
0063     case HIDPCONNADD:
0064         if (!capable(CAP_NET_ADMIN))
0065             return -EPERM;
0066 
0067         if (copy_from_user(&ca, argp, sizeof(ca)))
0068             return -EFAULT;
0069 
0070         csock = sockfd_lookup(ca.ctrl_sock, &err);
0071         if (!csock)
0072             return err;
0073 
0074         isock = sockfd_lookup(ca.intr_sock, &err);
0075         if (!isock) {
0076             sockfd_put(csock);
0077             return err;
0078         }
0079         ca.name[sizeof(ca.name)-1] = 0;
0080 
0081         err = hidp_connection_add(&ca, csock, isock);
0082         if (!err && copy_to_user(argp, &ca, sizeof(ca)))
0083             err = -EFAULT;
0084 
0085         sockfd_put(csock);
0086         sockfd_put(isock);
0087 
0088         return err;
0089 
0090     case HIDPCONNDEL:
0091         if (!capable(CAP_NET_ADMIN))
0092             return -EPERM;
0093 
0094         if (copy_from_user(&cd, argp, sizeof(cd)))
0095             return -EFAULT;
0096 
0097         return hidp_connection_del(&cd);
0098 
0099     case HIDPGETCONNLIST:
0100         if (copy_from_user(&cl, argp, sizeof(cl)))
0101             return -EFAULT;
0102 
0103         if (cl.cnum <= 0)
0104             return -EINVAL;
0105 
0106         err = hidp_get_connlist(&cl);
0107         if (!err && copy_to_user(argp, &cl, sizeof(cl)))
0108             return -EFAULT;
0109 
0110         return err;
0111 
0112     case HIDPGETCONNINFO:
0113         if (copy_from_user(&ci, argp, sizeof(ci)))
0114             return -EFAULT;
0115 
0116         err = hidp_get_conninfo(&ci);
0117         if (!err && copy_to_user(argp, &ci, sizeof(ci)))
0118             return -EFAULT;
0119 
0120         return err;
0121     }
0122 
0123     return -EINVAL;
0124 }
0125 
0126 static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
0127 {
0128     return do_hidp_sock_ioctl(sock, cmd, (void __user *)arg);
0129 }
0130 
0131 #ifdef CONFIG_COMPAT
0132 struct compat_hidp_connadd_req {
0133     int   ctrl_sock;    /* Connected control socket */
0134     int   intr_sock;    /* Connected interrupt socket */
0135     __u16 parser;
0136     __u16 rd_size;
0137     compat_uptr_t rd_data;
0138     __u8  country;
0139     __u8  subclass;
0140     __u16 vendor;
0141     __u16 product;
0142     __u16 version;
0143     __u32 flags;
0144     __u32 idle_to;
0145     char  name[128];
0146 };
0147 
0148 static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
0149 {
0150     void __user *argp = compat_ptr(arg);
0151     int err;
0152 
0153     if (cmd == HIDPGETCONNLIST) {
0154         struct hidp_connlist_req cl;
0155         u32 __user *p = argp;
0156         u32 uci;
0157 
0158         if (get_user(cl.cnum, p) || get_user(uci, p + 1))
0159             return -EFAULT;
0160 
0161         cl.ci = compat_ptr(uci);
0162 
0163         if (cl.cnum <= 0)
0164             return -EINVAL;
0165 
0166         err = hidp_get_connlist(&cl);
0167 
0168         if (!err && put_user(cl.cnum, p))
0169             err = -EFAULT;
0170 
0171         return err;
0172     } else if (cmd == HIDPCONNADD) {
0173         struct compat_hidp_connadd_req ca32;
0174         struct hidp_connadd_req ca;
0175         struct socket *csock;
0176         struct socket *isock;
0177 
0178         if (!capable(CAP_NET_ADMIN))
0179             return -EPERM;
0180 
0181         if (copy_from_user(&ca32, (void __user *) arg, sizeof(ca32)))
0182             return -EFAULT;
0183 
0184         ca.ctrl_sock = ca32.ctrl_sock;
0185         ca.intr_sock = ca32.intr_sock;
0186         ca.parser = ca32.parser;
0187         ca.rd_size = ca32.rd_size;
0188         ca.rd_data = compat_ptr(ca32.rd_data);
0189         ca.country = ca32.country;
0190         ca.subclass = ca32.subclass;
0191         ca.vendor = ca32.vendor;
0192         ca.product = ca32.product;
0193         ca.version = ca32.version;
0194         ca.flags = ca32.flags;
0195         ca.idle_to = ca32.idle_to;
0196         ca32.name[sizeof(ca32.name) - 1] = '\0';
0197         memcpy(ca.name, ca32.name, 128);
0198 
0199         csock = sockfd_lookup(ca.ctrl_sock, &err);
0200         if (!csock)
0201             return err;
0202 
0203         isock = sockfd_lookup(ca.intr_sock, &err);
0204         if (!isock) {
0205             sockfd_put(csock);
0206             return err;
0207         }
0208 
0209         err = hidp_connection_add(&ca, csock, isock);
0210         if (!err && copy_to_user(argp, &ca32, sizeof(ca32)))
0211             err = -EFAULT;
0212 
0213         sockfd_put(csock);
0214         sockfd_put(isock);
0215 
0216         return err;
0217     }
0218 
0219     return hidp_sock_ioctl(sock, cmd, arg);
0220 }
0221 #endif
0222 
0223 static const struct proto_ops hidp_sock_ops = {
0224     .family     = PF_BLUETOOTH,
0225     .owner      = THIS_MODULE,
0226     .release    = hidp_sock_release,
0227     .ioctl      = hidp_sock_ioctl,
0228 #ifdef CONFIG_COMPAT
0229     .compat_ioctl   = hidp_sock_compat_ioctl,
0230 #endif
0231     .bind       = sock_no_bind,
0232     .getname    = sock_no_getname,
0233     .sendmsg    = sock_no_sendmsg,
0234     .recvmsg    = sock_no_recvmsg,
0235     .listen     = sock_no_listen,
0236     .shutdown   = sock_no_shutdown,
0237     .connect    = sock_no_connect,
0238     .socketpair = sock_no_socketpair,
0239     .accept     = sock_no_accept,
0240     .mmap       = sock_no_mmap
0241 };
0242 
0243 static struct proto hidp_proto = {
0244     .name       = "HIDP",
0245     .owner      = THIS_MODULE,
0246     .obj_size   = sizeof(struct bt_sock)
0247 };
0248 
0249 static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
0250                 int kern)
0251 {
0252     struct sock *sk;
0253 
0254     BT_DBG("sock %p", sock);
0255 
0256     if (sock->type != SOCK_RAW)
0257         return -ESOCKTNOSUPPORT;
0258 
0259     sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, kern);
0260     if (!sk)
0261         return -ENOMEM;
0262 
0263     sock_init_data(sock, sk);
0264 
0265     sock->ops = &hidp_sock_ops;
0266 
0267     sock->state = SS_UNCONNECTED;
0268 
0269     sock_reset_flag(sk, SOCK_ZAPPED);
0270 
0271     sk->sk_protocol = protocol;
0272     sk->sk_state    = BT_OPEN;
0273 
0274     bt_sock_link(&hidp_sk_list, sk);
0275 
0276     return 0;
0277 }
0278 
0279 static const struct net_proto_family hidp_sock_family_ops = {
0280     .family = PF_BLUETOOTH,
0281     .owner  = THIS_MODULE,
0282     .create = hidp_sock_create
0283 };
0284 
0285 int __init hidp_init_sockets(void)
0286 {
0287     int err;
0288 
0289     err = proto_register(&hidp_proto, 0);
0290     if (err < 0)
0291         return err;
0292 
0293     err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
0294     if (err < 0) {
0295         BT_ERR("Can't register HIDP socket");
0296         goto error;
0297     }
0298 
0299     err = bt_procfs_init(&init_net, "hidp", &hidp_sk_list, NULL);
0300     if (err < 0) {
0301         BT_ERR("Failed to create HIDP proc file");
0302         bt_sock_unregister(BTPROTO_HIDP);
0303         goto error;
0304     }
0305 
0306     BT_INFO("HIDP socket layer initialized");
0307 
0308     return 0;
0309 
0310 error:
0311     proto_unregister(&hidp_proto);
0312     return err;
0313 }
0314 
0315 void __exit hidp_cleanup_sockets(void)
0316 {
0317     bt_procfs_cleanup(&init_net, "hidp");
0318     bt_sock_unregister(BTPROTO_HIDP);
0319     proto_unregister(&hidp_proto);
0320 }