cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

core.c (11201B)


      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/module.h>
     24
     25#include <linux/types.h>
     26#include <linux/errno.h>
     27#include <linux/kernel.h>
     28#include <linux/sched.h>
     29#include <linux/slab.h>
     30#include <linux/poll.h>
     31#include <linux/fcntl.h>
     32#include <linux/freezer.h>
     33#include <linux/skbuff.h>
     34#include <linux/socket.h>
     35#include <linux/ioctl.h>
     36#include <linux/file.h>
     37#include <linux/init.h>
     38#include <linux/kthread.h>
     39#include <net/sock.h>
     40
     41#include <linux/isdn/capilli.h>
     42
     43#include <net/bluetooth/bluetooth.h>
     44#include <net/bluetooth/l2cap.h>
     45
     46#include "cmtp.h"
     47
     48#define VERSION "1.0"
     49
     50static DECLARE_RWSEM(cmtp_session_sem);
     51static LIST_HEAD(cmtp_session_list);
     52
     53static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
     54{
     55	struct cmtp_session *session;
     56
     57	BT_DBG("");
     58
     59	list_for_each_entry(session, &cmtp_session_list, list)
     60		if (!bacmp(bdaddr, &session->bdaddr))
     61			return session;
     62
     63	return NULL;
     64}
     65
     66static void __cmtp_link_session(struct cmtp_session *session)
     67{
     68	list_add(&session->list, &cmtp_session_list);
     69}
     70
     71static void __cmtp_unlink_session(struct cmtp_session *session)
     72{
     73	list_del(&session->list);
     74}
     75
     76static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
     77{
     78	u32 valid_flags = BIT(CMTP_LOOPBACK);
     79	memset(ci, 0, sizeof(*ci));
     80	bacpy(&ci->bdaddr, &session->bdaddr);
     81
     82	ci->flags = session->flags & valid_flags;
     83	ci->state = session->state;
     84
     85	ci->num = session->num;
     86}
     87
     88
     89static inline int cmtp_alloc_block_id(struct cmtp_session *session)
     90{
     91	int i, id = -1;
     92
     93	for (i = 0; i < 16; i++)
     94		if (!test_and_set_bit(i, &session->blockids)) {
     95			id = i;
     96			break;
     97		}
     98
     99	return id;
    100}
    101
    102static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
    103{
    104	clear_bit(id, &session->blockids);
    105}
    106
    107static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
    108{
    109	struct sk_buff *skb = session->reassembly[id], *nskb;
    110	int size;
    111
    112	BT_DBG("session %p buf %p count %d", session, buf, count);
    113
    114	size = (skb) ? skb->len + count : count;
    115
    116	nskb = alloc_skb(size, GFP_ATOMIC);
    117	if (!nskb) {
    118		BT_ERR("Can't allocate memory for CAPI message");
    119		return;
    120	}
    121
    122	if (skb && (skb->len > 0))
    123		skb_copy_from_linear_data(skb, skb_put(nskb, skb->len), skb->len);
    124
    125	skb_put_data(nskb, buf, count);
    126
    127	session->reassembly[id] = nskb;
    128
    129	kfree_skb(skb);
    130}
    131
    132static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
    133{
    134	__u8 hdr, hdrlen, id;
    135	__u16 len;
    136
    137	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
    138
    139	while (skb->len > 0) {
    140		hdr = skb->data[0];
    141
    142		switch (hdr & 0xc0) {
    143		case 0x40:
    144			hdrlen = 2;
    145			len = skb->data[1];
    146			break;
    147		case 0x80:
    148			hdrlen = 3;
    149			len = skb->data[1] | (skb->data[2] << 8);
    150			break;
    151		default:
    152			hdrlen = 1;
    153			len = 0;
    154			break;
    155		}
    156
    157		id = (hdr & 0x3c) >> 2;
    158
    159		BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
    160
    161		if (hdrlen + len > skb->len) {
    162			BT_ERR("Wrong size or header information in CMTP frame");
    163			break;
    164		}
    165
    166		if (len == 0) {
    167			skb_pull(skb, hdrlen);
    168			continue;
    169		}
    170
    171		switch (hdr & 0x03) {
    172		case 0x00:
    173			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
    174			cmtp_recv_capimsg(session, session->reassembly[id]);
    175			session->reassembly[id] = NULL;
    176			break;
    177		case 0x01:
    178			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
    179			break;
    180		default:
    181			kfree_skb(session->reassembly[id]);
    182			session->reassembly[id] = NULL;
    183			break;
    184		}
    185
    186		skb_pull(skb, hdrlen + len);
    187	}
    188
    189	kfree_skb(skb);
    190	return 0;
    191}
    192
    193static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
    194{
    195	struct socket *sock = session->sock;
    196	struct kvec iv = { data, len };
    197	struct msghdr msg;
    198
    199	BT_DBG("session %p data %p len %d", session, data, len);
    200
    201	if (!len)
    202		return 0;
    203
    204	memset(&msg, 0, sizeof(msg));
    205
    206	return kernel_sendmsg(sock, &msg, &iv, 1, len);
    207}
    208
    209static void cmtp_process_transmit(struct cmtp_session *session)
    210{
    211	struct sk_buff *skb, *nskb;
    212	unsigned char *hdr;
    213	unsigned int size, tail;
    214
    215	BT_DBG("session %p", session);
    216
    217	nskb = alloc_skb(session->mtu, GFP_ATOMIC);
    218	if (!nskb) {
    219		BT_ERR("Can't allocate memory for new frame");
    220		return;
    221	}
    222
    223	while ((skb = skb_dequeue(&session->transmit))) {
    224		struct cmtp_scb *scb = (void *) skb->cb;
    225
    226		tail = session->mtu - nskb->len;
    227		if (tail < 5) {
    228			cmtp_send_frame(session, nskb->data, nskb->len);
    229			skb_trim(nskb, 0);
    230			tail = session->mtu;
    231		}
    232
    233		size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
    234
    235		if (scb->id < 0) {
    236			scb->id = cmtp_alloc_block_id(session);
    237			if (scb->id < 0) {
    238				skb_queue_head(&session->transmit, skb);
    239				break;
    240			}
    241		}
    242
    243		if (size < 256) {
    244			hdr = skb_put(nskb, 2);
    245			hdr[0] = 0x40
    246				| ((scb->id << 2) & 0x3c)
    247				| ((skb->len == size) ? 0x00 : 0x01);
    248			hdr[1] = size;
    249		} else {
    250			hdr = skb_put(nskb, 3);
    251			hdr[0] = 0x80
    252				| ((scb->id << 2) & 0x3c)
    253				| ((skb->len == size) ? 0x00 : 0x01);
    254			hdr[1] = size & 0xff;
    255			hdr[2] = size >> 8;
    256		}
    257
    258		skb_copy_from_linear_data(skb, skb_put(nskb, size), size);
    259		skb_pull(skb, size);
    260
    261		if (skb->len > 0) {
    262			skb_queue_head(&session->transmit, skb);
    263		} else {
    264			cmtp_free_block_id(session, scb->id);
    265			if (scb->data) {
    266				cmtp_send_frame(session, nskb->data, nskb->len);
    267				skb_trim(nskb, 0);
    268			}
    269			kfree_skb(skb);
    270		}
    271	}
    272
    273	cmtp_send_frame(session, nskb->data, nskb->len);
    274
    275	kfree_skb(nskb);
    276}
    277
    278static int cmtp_session(void *arg)
    279{
    280	struct cmtp_session *session = arg;
    281	struct sock *sk = session->sock->sk;
    282	struct sk_buff *skb;
    283	DEFINE_WAIT_FUNC(wait, woken_wake_function);
    284
    285	BT_DBG("session %p", session);
    286
    287	set_user_nice(current, -15);
    288
    289	add_wait_queue(sk_sleep(sk), &wait);
    290	while (1) {
    291		if (atomic_read(&session->terminate))
    292			break;
    293		if (sk->sk_state != BT_CONNECTED)
    294			break;
    295
    296		while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
    297			skb_orphan(skb);
    298			if (!skb_linearize(skb))
    299				cmtp_recv_frame(session, skb);
    300			else
    301				kfree_skb(skb);
    302		}
    303
    304		cmtp_process_transmit(session);
    305
    306		/*
    307		 * wait_woken() performs the necessary memory barriers
    308		 * for us; see the header comment for this primitive.
    309		 */
    310		wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
    311	}
    312	remove_wait_queue(sk_sleep(sk), &wait);
    313
    314	down_write(&cmtp_session_sem);
    315
    316	if (!(session->flags & BIT(CMTP_LOOPBACK)))
    317		cmtp_detach_device(session);
    318
    319	fput(session->sock->file);
    320
    321	__cmtp_unlink_session(session);
    322
    323	up_write(&cmtp_session_sem);
    324
    325	kfree(session);
    326	module_put_and_kthread_exit(0);
    327	return 0;
    328}
    329
    330int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
    331{
    332	u32 valid_flags = BIT(CMTP_LOOPBACK);
    333	struct cmtp_session *session, *s;
    334	int i, err;
    335
    336	BT_DBG("");
    337
    338	if (!l2cap_is_socket(sock))
    339		return -EBADFD;
    340
    341	if (req->flags & ~valid_flags)
    342		return -EINVAL;
    343
    344	session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
    345	if (!session)
    346		return -ENOMEM;
    347
    348	down_write(&cmtp_session_sem);
    349
    350	s = __cmtp_get_session(&l2cap_pi(sock->sk)->chan->dst);
    351	if (s && s->state == BT_CONNECTED) {
    352		err = -EEXIST;
    353		goto failed;
    354	}
    355
    356	bacpy(&session->bdaddr, &l2cap_pi(sock->sk)->chan->dst);
    357
    358	session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu,
    359					l2cap_pi(sock->sk)->chan->imtu);
    360
    361	BT_DBG("mtu %d", session->mtu);
    362
    363	sprintf(session->name, "%pMR", &session->bdaddr);
    364
    365	session->sock  = sock;
    366	session->state = BT_CONFIG;
    367
    368	init_waitqueue_head(&session->wait);
    369
    370	session->msgnum = CMTP_INITIAL_MSGNUM;
    371
    372	INIT_LIST_HEAD(&session->applications);
    373
    374	skb_queue_head_init(&session->transmit);
    375
    376	for (i = 0; i < 16; i++)
    377		session->reassembly[i] = NULL;
    378
    379	session->flags = req->flags;
    380
    381	__cmtp_link_session(session);
    382
    383	__module_get(THIS_MODULE);
    384	session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d",
    385								session->num);
    386	if (IS_ERR(session->task)) {
    387		module_put(THIS_MODULE);
    388		err = PTR_ERR(session->task);
    389		goto unlink;
    390	}
    391
    392	if (!(session->flags & BIT(CMTP_LOOPBACK))) {
    393		err = cmtp_attach_device(session);
    394		if (err < 0) {
    395			/* Caller will call fput in case of failure, and so
    396			 * will cmtp_session kthread.
    397			 */
    398			get_file(session->sock->file);
    399
    400			atomic_inc(&session->terminate);
    401			wake_up_interruptible(sk_sleep(session->sock->sk));
    402			up_write(&cmtp_session_sem);
    403			return err;
    404		}
    405	}
    406
    407	up_write(&cmtp_session_sem);
    408	return 0;
    409
    410unlink:
    411	__cmtp_unlink_session(session);
    412
    413failed:
    414	up_write(&cmtp_session_sem);
    415	kfree(session);
    416	return err;
    417}
    418
    419int cmtp_del_connection(struct cmtp_conndel_req *req)
    420{
    421	u32 valid_flags = 0;
    422	struct cmtp_session *session;
    423	int err = 0;
    424
    425	BT_DBG("");
    426
    427	if (req->flags & ~valid_flags)
    428		return -EINVAL;
    429
    430	down_read(&cmtp_session_sem);
    431
    432	session = __cmtp_get_session(&req->bdaddr);
    433	if (session) {
    434		/* Flush the transmit queue */
    435		skb_queue_purge(&session->transmit);
    436
    437		/* Stop session thread */
    438		atomic_inc(&session->terminate);
    439
    440		/*
    441		 * See the comment preceding the call to wait_woken()
    442		 * in cmtp_session().
    443		 */
    444		wake_up_interruptible(sk_sleep(session->sock->sk));
    445	} else
    446		err = -ENOENT;
    447
    448	up_read(&cmtp_session_sem);
    449	return err;
    450}
    451
    452int cmtp_get_connlist(struct cmtp_connlist_req *req)
    453{
    454	struct cmtp_session *session;
    455	int err = 0, n = 0;
    456
    457	BT_DBG("");
    458
    459	down_read(&cmtp_session_sem);
    460
    461	list_for_each_entry(session, &cmtp_session_list, list) {
    462		struct cmtp_conninfo ci;
    463
    464		__cmtp_copy_session(session, &ci);
    465
    466		if (copy_to_user(req->ci, &ci, sizeof(ci))) {
    467			err = -EFAULT;
    468			break;
    469		}
    470
    471		if (++n >= req->cnum)
    472			break;
    473
    474		req->ci++;
    475	}
    476	req->cnum = n;
    477
    478	up_read(&cmtp_session_sem);
    479	return err;
    480}
    481
    482int cmtp_get_conninfo(struct cmtp_conninfo *ci)
    483{
    484	struct cmtp_session *session;
    485	int err = 0;
    486
    487	down_read(&cmtp_session_sem);
    488
    489	session = __cmtp_get_session(&ci->bdaddr);
    490	if (session)
    491		__cmtp_copy_session(session, ci);
    492	else
    493		err = -ENOENT;
    494
    495	up_read(&cmtp_session_sem);
    496	return err;
    497}
    498
    499
    500static int __init cmtp_init(void)
    501{
    502	BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
    503
    504	return cmtp_init_sockets();
    505}
    506
    507static void __exit cmtp_exit(void)
    508{
    509	cmtp_cleanup_sockets();
    510}
    511
    512module_init(cmtp_init);
    513module_exit(cmtp_exit);
    514
    515MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
    516MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION);
    517MODULE_VERSION(VERSION);
    518MODULE_LICENSE("GPL");
    519MODULE_ALIAS("bt-proto-5");