1 /*
2    CMTP implementation for Linux Bluetooth stack (BlueZ).
3    Copyright (C) 2002-2003 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/config.h>
24 #include <linux/module.h>
25 
26 #include <linux/types.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #include <linux/major.h>
30 #include <linux/sched.h>
31 #include <linux/slab.h>
32 #include <linux/poll.h>
33 #include <linux/fcntl.h>
34 #include <linux/skbuff.h>
35 #include <linux/socket.h>
36 #include <linux/ioctl.h>
37 #include <linux/file.h>
38 #include <net/sock.h>
39 
40 #include <asm/system.h>
41 #include <asm/uaccess.h>
42 
43 #include "cmtp.h"
44 
45 #ifndef CONFIG_BLUEZ_CMTP_DEBUG
46 #undef  BT_DBG
47 #define BT_DBG(D...)
48 #endif
49 
cmtp_sock_release(struct socket * sock)50 static int cmtp_sock_release(struct socket *sock)
51 {
52 	struct sock *sk = sock->sk;
53 
54 	BT_DBG("sock %p sk %p", sock, sk);
55 
56 	if (!sk)
57 		return 0;
58 
59 	sock_orphan(sk);
60 	sock_put(sk);
61 
62 	MOD_DEC_USE_COUNT;
63 	return 0;
64 }
65 
cmtp_sock_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)66 static 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 	int err;
74 
75 	BT_DBG("cmd %x arg %lx", cmd, arg);
76 
77 	switch (cmd) {
78 	case CMTPCONNADD:
79 		if (!capable(CAP_NET_ADMIN))
80 			return -EACCES;
81 
82 		if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
83 			return -EFAULT;
84 
85 		nsock = sockfd_lookup(ca.sock, &err);
86 		if (!nsock)
87 			return err;
88 
89 		if (nsock->sk->state != BT_CONNECTED) {
90 			fput(nsock->file);
91 			return -EBADFD;
92 		}
93 
94 		err = cmtp_add_connection(&ca, nsock);
95 		if (!err) {
96 			if (copy_to_user((void *) arg, &ca, sizeof(ca)))
97 				err = -EFAULT;
98 		} else
99 			fput(nsock->file);
100 
101 		return err;
102 
103 	case CMTPCONNDEL:
104 		if (!capable(CAP_NET_ADMIN))
105 			return -EACCES;
106 
107 		if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
108 			return -EFAULT;
109 
110 		return cmtp_del_connection(&cd);
111 
112 	case CMTPGETCONNLIST:
113 		if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
114 			return -EFAULT;
115 
116 		if (cl.cnum <= 0)
117 			return -EINVAL;
118 
119 		err = cmtp_get_connlist(&cl);
120 		if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
121 			return -EFAULT;
122 
123 		return err;
124 
125 	case CMTPGETCONNINFO:
126 		if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
127 			return -EFAULT;
128 
129 		err = cmtp_get_conninfo(&ci);
130 		if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
131 			return -EFAULT;
132 
133 		return err;
134 	}
135 
136 	return -EINVAL;
137 }
138 
139 static struct proto_ops cmtp_sock_ops = {
140 	family:		PF_BLUETOOTH,
141 	release:	cmtp_sock_release,
142 	ioctl:		cmtp_sock_ioctl,
143 	bind:		sock_no_bind,
144 	getname:	sock_no_getname,
145 	sendmsg:	sock_no_sendmsg,
146 	recvmsg:	sock_no_recvmsg,
147 	poll:		sock_no_poll,
148 	listen:		sock_no_listen,
149 	shutdown:	sock_no_shutdown,
150 	setsockopt:	sock_no_setsockopt,
151 	getsockopt:	sock_no_getsockopt,
152 	connect:	sock_no_connect,
153 	socketpair:	sock_no_socketpair,
154 	accept:		sock_no_accept,
155 	mmap:		sock_no_mmap
156 };
157 
cmtp_sock_create(struct socket * sock,int protocol)158 static int cmtp_sock_create(struct socket *sock, int protocol)
159 {
160 	struct sock *sk;
161 
162 	BT_DBG("sock %p", sock);
163 
164 	if (sock->type != SOCK_RAW)
165 		return -ESOCKTNOSUPPORT;
166 
167 	sock->ops = &cmtp_sock_ops;
168 
169 	if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
170 		return -ENOMEM;
171 
172 	MOD_INC_USE_COUNT;
173 
174 	sock->state = SS_UNCONNECTED;
175 	sock_init_data(sock, sk);
176 
177 	sk->destruct = NULL;
178 	sk->protocol = protocol;
179 
180 	return 0;
181 }
182 
183 static struct net_proto_family cmtp_sock_family_ops = {
184 	family:		PF_BLUETOOTH,
185 	create:		cmtp_sock_create
186 };
187 
cmtp_init_sockets(void)188 int cmtp_init_sockets(void)
189 {
190 	int err;
191 
192 	if ((err = bluez_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops))) {
193 		BT_ERR("Can't register CMTP socket layer (%d)", err);
194 		return err;
195 	}
196 
197 	return 0;
198 }
199 
cmtp_cleanup_sockets(void)200 void cmtp_cleanup_sockets(void)
201 {
202 	int err;
203 
204 	if ((err = bluez_sock_unregister(BTPROTO_CMTP)))
205 		BT_ERR("Can't unregister CMTP socket layer (%d)", err);
206 
207 	return;
208 }
209