1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/module.h>
24
25#include <linux/types.h>
26#include <linux/capability.h>
27#include <linux/errno.h>
28#include <linux/kernel.h>
29#include <linux/slab.h>
30#include <linux/poll.h>
31#include <linux/fcntl.h>
32#include <linux/skbuff.h>
33#include <linux/socket.h>
34#include <linux/ioctl.h>
35#include <linux/file.h>
36#include <linux/compat.h>
37#include <net/sock.h>
38
39#include <linux/isdn/capilli.h>
40
41#include <asm/system.h>
42#include <asm/uaccess.h>
43
44#include "cmtp.h"
45
46#ifndef CONFIG_BT_CMTP_DEBUG
47#undef BT_DBG
48#define BT_DBG(D...)
49#endif
50
51static int cmtp_sock_release(struct socket *sock)
52{
53 struct sock *sk = sock->sk;
54
55 BT_DBG("sock %p sk %p", sock, sk);
56
57 if (!sk)
58 return 0;
59
60 sock_orphan(sk);
61 sock_put(sk);
62
63 return 0;
64}
65
66static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
67{
68 struct cmtp_connadd_req ca;
69 struct cmtp_conndel_req cd;
70 struct cmtp_connlist_req cl;
71 struct cmtp_conninfo ci;
72 struct socket *nsock;
73 void __user *argp = (void __user *)arg;
74 int err;
75
76 BT_DBG("cmd %x arg %lx", cmd, arg);
77
78 switch (cmd) {
79 case CMTPCONNADD:
80 if (!capable(CAP_NET_ADMIN))
81 return -EACCES;
82
83 if (copy_from_user(&ca, argp, sizeof(ca)))
84 return -EFAULT;
85
86 nsock = sockfd_lookup(ca.sock, &err);
87 if (!nsock)
88 return err;
89
90 if (nsock->sk->sk_state != BT_CONNECTED) {
91 sockfd_put(nsock);
92 return -EBADFD;
93 }
94
95 err = cmtp_add_connection(&ca, nsock);
96 if (!err) {
97 if (copy_to_user(argp, &ca, sizeof(ca)))
98 err = -EFAULT;
99 } else
100 sockfd_put(nsock);
101
102 return err;
103
104 case CMTPCONNDEL:
105 if (!capable(CAP_NET_ADMIN))
106 return -EACCES;
107
108 if (copy_from_user(&cd, argp, sizeof(cd)))
109 return -EFAULT;
110
111 return cmtp_del_connection(&cd);
112
113 case CMTPGETCONNLIST:
114 if (copy_from_user(&cl, argp, sizeof(cl)))
115 return -EFAULT;
116
117 if (cl.cnum <= 0)
118 return -EINVAL;
119
120 err = cmtp_get_connlist(&cl);
121 if (!err && copy_to_user(argp, &cl, sizeof(cl)))
122 return -EFAULT;
123
124 return err;
125
126 case CMTPGETCONNINFO:
127 if (copy_from_user(&ci, argp, sizeof(ci)))
128 return -EFAULT;
129
130 err = cmtp_get_conninfo(&ci);
131 if (!err && copy_to_user(argp, &ci, sizeof(ci)))
132 return -EFAULT;
133
134 return err;
135 }
136
137 return -EINVAL;
138}
139
140#ifdef CONFIG_COMPAT
141static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
142{
143 if (cmd == CMTPGETCONNLIST) {
144 struct cmtp_connlist_req cl;
145 uint32_t uci;
146 int err;
147
148 if (get_user(cl.cnum, (uint32_t __user *) arg) ||
149 get_user(uci, (u32 __user *) (arg + 4)))
150 return -EFAULT;
151
152 cl.ci = compat_ptr(uci);
153
154 if (cl.cnum <= 0)
155 return -EINVAL;
156
157 err = cmtp_get_connlist(&cl);
158
159 if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
160 err = -EFAULT;
161
162 return err;
163 }
164
165 return cmtp_sock_ioctl(sock, cmd, arg);
166}
167#endif
168
169static const struct proto_ops cmtp_sock_ops = {
170 .family = PF_BLUETOOTH,
171 .owner = THIS_MODULE,
172 .release = cmtp_sock_release,
173 .ioctl = cmtp_sock_ioctl,
174#ifdef CONFIG_COMPAT
175 .compat_ioctl = cmtp_sock_compat_ioctl,
176#endif
177 .bind = sock_no_bind,
178 .getname = sock_no_getname,
179 .sendmsg = sock_no_sendmsg,
180 .recvmsg = sock_no_recvmsg,
181 .poll = sock_no_poll,
182 .listen = sock_no_listen,
183 .shutdown = sock_no_shutdown,
184 .setsockopt = sock_no_setsockopt,
185 .getsockopt = sock_no_getsockopt,
186 .connect = sock_no_connect,
187 .socketpair = sock_no_socketpair,
188 .accept = sock_no_accept,
189 .mmap = sock_no_mmap
190};
191
192static struct proto cmtp_proto = {
193 .name = "CMTP",
194 .owner = THIS_MODULE,
195 .obj_size = sizeof(struct bt_sock)
196};
197
198static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol)
199{
200 struct sock *sk;
201
202 BT_DBG("sock %p", sock);
203
204 if (sock->type != SOCK_RAW)
205 return -ESOCKTNOSUPPORT;
206
207 sk = sk_alloc(net, PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto);
208 if (!sk)
209 return -ENOMEM;
210
211 sock_init_data(sock, sk);
212
213 sock->ops = &cmtp_sock_ops;
214
215 sock->state = SS_UNCONNECTED;
216
217 sock_reset_flag(sk, SOCK_ZAPPED);
218
219 sk->sk_protocol = protocol;
220 sk->sk_state = BT_OPEN;
221
222 return 0;
223}
224
225static struct net_proto_family cmtp_sock_family_ops = {
226 .family = PF_BLUETOOTH,
227 .owner = THIS_MODULE,
228 .create = cmtp_sock_create
229};
230
231int cmtp_init_sockets(void)
232{
233 int err;
234
235 err = proto_register(&cmtp_proto, 0);
236 if (err < 0)
237 return err;
238
239 err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
240 if (err < 0)
241 goto error;
242
243 return 0;
244
245error:
246 BT_ERR("Can't register CMTP socket");
247 proto_unregister(&cmtp_proto);
248 return err;
249}
250
251void cmtp_cleanup_sockets(void)
252{
253 if (bt_sock_unregister(BTPROTO_CMTP) < 0)
254 BT_ERR("Can't unregister CMTP socket");
255
256 proto_unregister(&cmtp_proto);
257}
258