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

mgmt_util.c (7282B)


      1/*
      2   BlueZ - Bluetooth protocol stack for Linux
      3
      4   Copyright (C) 2015  Intel Corporation
      5
      6   This program is free software; you can redistribute it and/or modify
      7   it under the terms of the GNU General Public License version 2 as
      8   published by the Free Software Foundation;
      9
     10   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     11   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     12   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
     13   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
     14   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
     15   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18
     19   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
     20   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
     21   SOFTWARE IS DISCLAIMED.
     22*/
     23
     24#include <asm/unaligned.h>
     25
     26#include <net/bluetooth/bluetooth.h>
     27#include <net/bluetooth/hci_core.h>
     28#include <net/bluetooth/hci_mon.h>
     29#include <net/bluetooth/mgmt.h>
     30
     31#include "mgmt_util.h"
     32
     33static struct sk_buff *create_monitor_ctrl_event(__le16 index, u32 cookie,
     34						 u16 opcode, u16 len, void *buf)
     35{
     36	struct hci_mon_hdr *hdr;
     37	struct sk_buff *skb;
     38
     39	skb = bt_skb_alloc(6 + len, GFP_ATOMIC);
     40	if (!skb)
     41		return NULL;
     42
     43	put_unaligned_le32(cookie, skb_put(skb, 4));
     44	put_unaligned_le16(opcode, skb_put(skb, 2));
     45
     46	if (buf)
     47		skb_put_data(skb, buf, len);
     48
     49	__net_timestamp(skb);
     50
     51	hdr = skb_push(skb, HCI_MON_HDR_SIZE);
     52	hdr->opcode = cpu_to_le16(HCI_MON_CTRL_EVENT);
     53	hdr->index = index;
     54	hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
     55
     56	return skb;
     57}
     58
     59struct sk_buff *mgmt_alloc_skb(struct hci_dev *hdev, u16 opcode,
     60			       unsigned int size)
     61{
     62	struct sk_buff *skb;
     63
     64	skb = alloc_skb(sizeof(struct mgmt_hdr) + size, GFP_KERNEL);
     65	if (!skb)
     66		return skb;
     67
     68	skb_reserve(skb, sizeof(struct mgmt_hdr));
     69	bt_cb(skb)->mgmt.hdev = hdev;
     70	bt_cb(skb)->mgmt.opcode = opcode;
     71
     72	return skb;
     73}
     74
     75int mgmt_send_event_skb(unsigned short channel, struct sk_buff *skb, int flag,
     76			struct sock *skip_sk)
     77{
     78	struct hci_dev *hdev;
     79	struct mgmt_hdr *hdr;
     80	int len;
     81
     82	if (!skb)
     83		return -EINVAL;
     84
     85	len = skb->len;
     86	hdev = bt_cb(skb)->mgmt.hdev;
     87
     88	/* Time stamp */
     89	__net_timestamp(skb);
     90
     91	/* Send just the data, without headers, to the monitor */
     92	if (channel == HCI_CHANNEL_CONTROL)
     93		hci_send_monitor_ctrl_event(hdev, bt_cb(skb)->mgmt.opcode,
     94					    skb->data, skb->len,
     95					    skb_get_ktime(skb), flag, skip_sk);
     96
     97	hdr = skb_push(skb, sizeof(*hdr));
     98	hdr->opcode = cpu_to_le16(bt_cb(skb)->mgmt.opcode);
     99	if (hdev)
    100		hdr->index = cpu_to_le16(hdev->id);
    101	else
    102		hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
    103	hdr->len = cpu_to_le16(len);
    104
    105	hci_send_to_channel(channel, skb, flag, skip_sk);
    106
    107	kfree_skb(skb);
    108	return 0;
    109}
    110
    111int mgmt_send_event(u16 event, struct hci_dev *hdev, unsigned short channel,
    112		    void *data, u16 data_len, int flag, struct sock *skip_sk)
    113{
    114	struct sk_buff *skb;
    115
    116	skb = mgmt_alloc_skb(hdev, event, data_len);
    117	if (!skb)
    118		return -ENOMEM;
    119
    120	if (data)
    121		skb_put_data(skb, data, data_len);
    122
    123	return mgmt_send_event_skb(channel, skb, flag, skip_sk);
    124}
    125
    126int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
    127{
    128	struct sk_buff *skb, *mskb;
    129	struct mgmt_hdr *hdr;
    130	struct mgmt_ev_cmd_status *ev;
    131	int err;
    132
    133	BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
    134
    135	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
    136	if (!skb)
    137		return -ENOMEM;
    138
    139	hdr = skb_put(skb, sizeof(*hdr));
    140
    141	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
    142	hdr->index = cpu_to_le16(index);
    143	hdr->len = cpu_to_le16(sizeof(*ev));
    144
    145	ev = skb_put(skb, sizeof(*ev));
    146	ev->status = status;
    147	ev->opcode = cpu_to_le16(cmd);
    148
    149	mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
    150					 MGMT_EV_CMD_STATUS, sizeof(*ev), ev);
    151	if (mskb)
    152		skb->tstamp = mskb->tstamp;
    153	else
    154		__net_timestamp(skb);
    155
    156	err = sock_queue_rcv_skb(sk, skb);
    157	if (err < 0)
    158		kfree_skb(skb);
    159
    160	if (mskb) {
    161		hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
    162				    HCI_SOCK_TRUSTED, NULL);
    163		kfree_skb(mskb);
    164	}
    165
    166	return err;
    167}
    168
    169int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
    170		      void *rp, size_t rp_len)
    171{
    172	struct sk_buff *skb, *mskb;
    173	struct mgmt_hdr *hdr;
    174	struct mgmt_ev_cmd_complete *ev;
    175	int err;
    176
    177	BT_DBG("sock %p", sk);
    178
    179	skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
    180	if (!skb)
    181		return -ENOMEM;
    182
    183	hdr = skb_put(skb, sizeof(*hdr));
    184
    185	hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
    186	hdr->index = cpu_to_le16(index);
    187	hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
    188
    189	ev = skb_put(skb, sizeof(*ev) + rp_len);
    190	ev->opcode = cpu_to_le16(cmd);
    191	ev->status = status;
    192
    193	if (rp)
    194		memcpy(ev->data, rp, rp_len);
    195
    196	mskb = create_monitor_ctrl_event(hdr->index, hci_sock_get_cookie(sk),
    197					 MGMT_EV_CMD_COMPLETE,
    198					 sizeof(*ev) + rp_len, ev);
    199	if (mskb)
    200		skb->tstamp = mskb->tstamp;
    201	else
    202		__net_timestamp(skb);
    203
    204	err = sock_queue_rcv_skb(sk, skb);
    205	if (err < 0)
    206		kfree_skb(skb);
    207
    208	if (mskb) {
    209		hci_send_to_channel(HCI_CHANNEL_MONITOR, mskb,
    210				    HCI_SOCK_TRUSTED, NULL);
    211		kfree_skb(mskb);
    212	}
    213
    214	return err;
    215}
    216
    217struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
    218					   struct hci_dev *hdev)
    219{
    220	struct mgmt_pending_cmd *cmd;
    221
    222	list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
    223		if (hci_sock_get_channel(cmd->sk) != channel)
    224			continue;
    225		if (cmd->opcode == opcode)
    226			return cmd;
    227	}
    228
    229	return NULL;
    230}
    231
    232struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel,
    233						u16 opcode,
    234						struct hci_dev *hdev,
    235						const void *data)
    236{
    237	struct mgmt_pending_cmd *cmd;
    238
    239	list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
    240		if (cmd->user_data != data)
    241			continue;
    242		if (cmd->opcode == opcode)
    243			return cmd;
    244	}
    245
    246	return NULL;
    247}
    248
    249void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
    250			  void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
    251			  void *data)
    252{
    253	struct mgmt_pending_cmd *cmd, *tmp;
    254
    255	list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
    256		if (opcode > 0 && cmd->opcode != opcode)
    257			continue;
    258
    259		cb(cmd, data);
    260	}
    261}
    262
    263struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
    264					  struct hci_dev *hdev,
    265					  void *data, u16 len)
    266{
    267	struct mgmt_pending_cmd *cmd;
    268
    269	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
    270	if (!cmd)
    271		return NULL;
    272
    273	cmd->opcode = opcode;
    274	cmd->index = hdev->id;
    275
    276	cmd->param = kmemdup(data, len, GFP_KERNEL);
    277	if (!cmd->param) {
    278		kfree(cmd);
    279		return NULL;
    280	}
    281
    282	cmd->param_len = len;
    283
    284	cmd->sk = sk;
    285	sock_hold(sk);
    286
    287	return cmd;
    288}
    289
    290struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
    291					  struct hci_dev *hdev,
    292					  void *data, u16 len)
    293{
    294	struct mgmt_pending_cmd *cmd;
    295
    296	cmd = mgmt_pending_new(sk, opcode, hdev, data, len);
    297	if (!cmd)
    298		return NULL;
    299
    300	list_add_tail(&cmd->list, &hdev->mgmt_pending);
    301
    302	return cmd;
    303}
    304
    305void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
    306{
    307	sock_put(cmd->sk);
    308	kfree(cmd->param);
    309	kfree(cmd);
    310}
    311
    312void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
    313{
    314	list_del(&cmd->list);
    315	mgmt_pending_free(cmd);
    316}