SOFTWARE IS DISCLAIMED.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/socket.h>
#include <linux/ioctl.h>
#include <linux/file.h>
+#include <linux/compat.h>
#include <net/sock.h>
#include <linux/isdn/capilli.h>
struct cmtp_connlist_req cl;
struct cmtp_conninfo ci;
struct socket *nsock;
+ void __user *argp = (void __user *)arg;
int err;
BT_DBG("cmd %x arg %lx", cmd, arg);
if (!capable(CAP_NET_ADMIN))
return -EACCES;
- if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
+ if (copy_from_user(&ca, argp, sizeof(ca)))
return -EFAULT;
nsock = sockfd_lookup(ca.sock, &err);
err = cmtp_add_connection(&ca, nsock);
if (!err) {
- if (copy_to_user((void *) arg, &ca, sizeof(ca)))
+ if (copy_to_user(argp, &ca, sizeof(ca)))
err = -EFAULT;
} else
fput(nsock->file);
if (!capable(CAP_NET_ADMIN))
return -EACCES;
- if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
+ if (copy_from_user(&cd, argp, sizeof(cd)))
return -EFAULT;
return cmtp_del_connection(&cd);
case CMTPGETCONNLIST:
- if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
+ if (copy_from_user(&cl, argp, sizeof(cl)))
return -EFAULT;
if (cl.cnum <= 0)
return -EINVAL;
err = cmtp_get_connlist(&cl);
- if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
+ if (!err && copy_to_user(argp, &cl, sizeof(cl)))
return -EFAULT;
return err;
case CMTPGETCONNINFO:
- if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
+ if (copy_from_user(&ci, argp, sizeof(ci)))
return -EFAULT;
err = cmtp_get_conninfo(&ci);
- if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
+ if (!err && copy_to_user(argp, &ci, sizeof(ci)))
return -EFAULT;
return err;
return -EINVAL;
}
-static struct proto_ops cmtp_sock_ops = {
+#ifdef CONFIG_COMPAT
+static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == CMTPGETCONNLIST) {
+ struct cmtp_connlist_req cl;
+ uint32_t uci;
+ int err;
+
+ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+ get_user(uci, (u32 __user *) (arg + 4)))
+ return -EFAULT;
+
+ cl.ci = compat_ptr(uci);
+
+ if (cl.cnum <= 0)
+ return -EINVAL;
+
+ err = cmtp_get_connlist(&cl);
+
+ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+ err = -EFAULT;
+
+ return err;
+ }
+
+ return cmtp_sock_ioctl(sock, cmd, arg);
+}
+#endif
+
+static const struct proto_ops cmtp_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = cmtp_sock_release,
.ioctl = cmtp_sock_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = cmtp_sock_compat_ioctl,
+#endif
.bind = sock_no_bind,
.getname = sock_no_getname,
.sendmsg = sock_no_sendmsg,
.mmap = sock_no_mmap
};
+static struct proto cmtp_proto = {
+ .name = "CMTP",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct bt_sock)
+};
+
static int cmtp_sock_create(struct socket *sock, int protocol)
{
struct sock *sk;
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
- if (!(sk = bt_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
+ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1);
+ if (!sk)
return -ENOMEM;
- sk_set_owner(sk, THIS_MODULE);
+ sock_init_data(sock, sk);
sock->ops = &cmtp_sock_ops;
sock->state = SS_UNCONNECTED;
- sk->sk_destruct = NULL;
+ sock_reset_flag(sk, SOCK_ZAPPED);
+
sk->sk_protocol = protocol;
+ sk->sk_state = BT_OPEN;
return 0;
}
int cmtp_init_sockets(void)
{
- bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
+ int err;
+
+ err = proto_register(&cmtp_proto, 0);
+ if (err < 0)
+ return err;
+
+ err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
+ if (err < 0)
+ goto error;
return 0;
+
+error:
+ BT_ERR("Can't register CMTP socket");
+ proto_unregister(&cmtp_proto);
+ return err;
}
void cmtp_cleanup_sockets(void)
{
- if (bt_sock_unregister(BTPROTO_CMTP))
+ if (bt_sock_unregister(BTPROTO_CMTP) < 0)
BT_ERR("Can't unregister CMTP socket");
+
+ proto_unregister(&cmtp_proto);
}