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

command.c (8335B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2012  Intel Corporation. All rights reserved.
      4 */
      5
      6#define pr_fmt(fmt) "hci: %s: " fmt, __func__
      7
      8#include <linux/init.h>
      9#include <linux/kernel.h>
     10#include <linux/sched.h>
     11#include <linux/module.h>
     12
     13#include <net/nfc/hci.h>
     14
     15#include "hci.h"
     16
     17#define MAX_FWI 4949
     18
     19static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
     20			       const u8 *param, size_t param_len,
     21			       data_exchange_cb_t cb, void *cb_context)
     22{
     23	pr_debug("exec cmd async through pipe=%d, cmd=%d, plen=%zd\n", pipe,
     24		 cmd, param_len);
     25
     26	/* TODO: Define hci cmd execution delay. Should it be the same
     27	 * for all commands?
     28	 */
     29	return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_COMMAND, cmd,
     30				      param, param_len, cb, cb_context, MAX_FWI);
     31}
     32
     33/*
     34 * HCI command execution completion callback.
     35 * err will be a standard linux error (may be converted from HCI response)
     36 * skb contains the response data and must be disposed, or may be NULL if
     37 * an error occurred
     38 */
     39static void nfc_hci_execute_cb(void *context, struct sk_buff *skb, int err)
     40{
     41	struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)context;
     42
     43	pr_debug("HCI Cmd completed with result=%d\n", err);
     44
     45	hcp_ew->exec_result = err;
     46	if (hcp_ew->exec_result == 0)
     47		hcp_ew->result_skb = skb;
     48	else
     49		kfree_skb(skb);
     50	hcp_ew->exec_complete = true;
     51
     52	wake_up(hcp_ew->wq);
     53}
     54
     55static int nfc_hci_execute_cmd(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
     56			       const u8 *param, size_t param_len,
     57			       struct sk_buff **skb)
     58{
     59	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(ew_wq);
     60	struct hcp_exec_waiter hcp_ew;
     61	hcp_ew.wq = &ew_wq;
     62	hcp_ew.exec_complete = false;
     63	hcp_ew.result_skb = NULL;
     64
     65	pr_debug("exec cmd sync through pipe=%d, cmd=%d, plen=%zd\n", pipe,
     66		 cmd, param_len);
     67
     68	/* TODO: Define hci cmd execution delay. Should it be the same
     69	 * for all commands?
     70	 */
     71	hcp_ew.exec_result = nfc_hci_hcp_message_tx(hdev, pipe,
     72						    NFC_HCI_HCP_COMMAND, cmd,
     73						    param, param_len,
     74						    nfc_hci_execute_cb, &hcp_ew,
     75						    MAX_FWI);
     76	if (hcp_ew.exec_result < 0)
     77		return hcp_ew.exec_result;
     78
     79	wait_event(ew_wq, hcp_ew.exec_complete == true);
     80
     81	if (hcp_ew.exec_result == 0) {
     82		if (skb)
     83			*skb = hcp_ew.result_skb;
     84		else
     85			kfree_skb(hcp_ew.result_skb);
     86	}
     87
     88	return hcp_ew.exec_result;
     89}
     90
     91int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
     92		       const u8 *param, size_t param_len)
     93{
     94	u8 pipe;
     95
     96	pr_debug("%d to gate %d\n", event, gate);
     97
     98	pipe = hdev->gate2pipe[gate];
     99	if (pipe == NFC_HCI_INVALID_PIPE)
    100		return -EADDRNOTAVAIL;
    101
    102	return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_EVENT, event,
    103				      param, param_len, NULL, NULL, 0);
    104}
    105EXPORT_SYMBOL(nfc_hci_send_event);
    106
    107/*
    108 * Execute an hci command sent to gate.
    109 * skb will contain response data if success. skb can be NULL if you are not
    110 * interested by the response.
    111 */
    112int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
    113		     const u8 *param, size_t param_len, struct sk_buff **skb)
    114{
    115	u8 pipe;
    116
    117	pipe = hdev->gate2pipe[gate];
    118	if (pipe == NFC_HCI_INVALID_PIPE)
    119		return -EADDRNOTAVAIL;
    120
    121	return nfc_hci_execute_cmd(hdev, pipe, cmd, param, param_len, skb);
    122}
    123EXPORT_SYMBOL(nfc_hci_send_cmd);
    124
    125int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
    126			   const u8 *param, size_t param_len,
    127			   data_exchange_cb_t cb, void *cb_context)
    128{
    129	u8 pipe;
    130
    131	pipe = hdev->gate2pipe[gate];
    132	if (pipe == NFC_HCI_INVALID_PIPE)
    133		return -EADDRNOTAVAIL;
    134
    135	return nfc_hci_execute_cmd_async(hdev, pipe, cmd, param, param_len,
    136					 cb, cb_context);
    137}
    138EXPORT_SYMBOL(nfc_hci_send_cmd_async);
    139
    140int nfc_hci_set_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx,
    141		      const u8 *param, size_t param_len)
    142{
    143	int r;
    144	u8 *tmp;
    145
    146	/* TODO ELa: reg idx must be inserted before param, but we don't want
    147	 * to ask the caller to do it to keep a simpler API.
    148	 * For now, just create a new temporary param buffer. This is far from
    149	 * optimal though, and the plan is to modify APIs to pass idx down to
    150	 * nfc_hci_hcp_message_tx where the frame is actually built, thereby
    151	 * eliminating the need for the temp allocation-copy here.
    152	 */
    153
    154	pr_debug("idx=%d to gate %d\n", idx, gate);
    155
    156	tmp = kmalloc(1 + param_len, GFP_KERNEL);
    157	if (tmp == NULL)
    158		return -ENOMEM;
    159
    160	*tmp = idx;
    161	memcpy(tmp + 1, param, param_len);
    162
    163	r = nfc_hci_send_cmd(hdev, gate, NFC_HCI_ANY_SET_PARAMETER,
    164			     tmp, param_len + 1, NULL);
    165
    166	kfree(tmp);
    167
    168	return r;
    169}
    170EXPORT_SYMBOL(nfc_hci_set_param);
    171
    172int nfc_hci_get_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx,
    173		      struct sk_buff **skb)
    174{
    175	pr_debug("gate=%d regidx=%d\n", gate, idx);
    176
    177	return nfc_hci_send_cmd(hdev, gate, NFC_HCI_ANY_GET_PARAMETER,
    178				&idx, 1, skb);
    179}
    180EXPORT_SYMBOL(nfc_hci_get_param);
    181
    182static int nfc_hci_open_pipe(struct nfc_hci_dev *hdev, u8 pipe)
    183{
    184	struct sk_buff *skb;
    185	int r;
    186
    187	pr_debug("pipe=%d\n", pipe);
    188
    189	r = nfc_hci_execute_cmd(hdev, pipe, NFC_HCI_ANY_OPEN_PIPE,
    190				NULL, 0, &skb);
    191	if (r == 0) {
    192		/* dest host other than host controller will send
    193		 * number of pipes already open on this gate before
    194		 * execution. The number can be found in skb->data[0]
    195		 */
    196		kfree_skb(skb);
    197	}
    198
    199	return r;
    200}
    201
    202static int nfc_hci_close_pipe(struct nfc_hci_dev *hdev, u8 pipe)
    203{
    204	return nfc_hci_execute_cmd(hdev, pipe, NFC_HCI_ANY_CLOSE_PIPE,
    205				   NULL, 0, NULL);
    206}
    207
    208static u8 nfc_hci_create_pipe(struct nfc_hci_dev *hdev, u8 dest_host,
    209			      u8 dest_gate, int *result)
    210{
    211	struct sk_buff *skb;
    212	struct hci_create_pipe_params params;
    213	struct hci_create_pipe_resp *resp;
    214	u8 pipe;
    215
    216	pr_debug("gate=%d\n", dest_gate);
    217
    218	params.src_gate = NFC_HCI_ADMIN_GATE;
    219	params.dest_host = dest_host;
    220	params.dest_gate = dest_gate;
    221
    222	*result = nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
    223				      NFC_HCI_ADM_CREATE_PIPE,
    224				      (u8 *) &params, sizeof(params), &skb);
    225	if (*result < 0)
    226		return NFC_HCI_INVALID_PIPE;
    227
    228	resp = (struct hci_create_pipe_resp *)skb->data;
    229	pipe = resp->pipe;
    230	kfree_skb(skb);
    231
    232	pr_debug("pipe created=%d\n", pipe);
    233
    234	return pipe;
    235}
    236
    237static int nfc_hci_delete_pipe(struct nfc_hci_dev *hdev, u8 pipe)
    238{
    239	return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
    240				   NFC_HCI_ADM_DELETE_PIPE, &pipe, 1, NULL);
    241}
    242
    243static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
    244{
    245	u8 param[2];
    246	size_t param_len = 2;
    247
    248	/* TODO: Find out what the identity reference data is
    249	 * and fill param with it. HCI spec 6.1.3.5 */
    250
    251	if (test_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &hdev->quirks))
    252		param_len = 0;
    253
    254	return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
    255				   NFC_HCI_ADM_CLEAR_ALL_PIPE, param, param_len,
    256				   NULL);
    257}
    258
    259int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate)
    260{
    261	int r;
    262	u8 pipe = hdev->gate2pipe[gate];
    263
    264	if (pipe == NFC_HCI_INVALID_PIPE)
    265		return -EADDRNOTAVAIL;
    266
    267	r = nfc_hci_close_pipe(hdev, pipe);
    268	if (r < 0)
    269		return r;
    270
    271	if (pipe != NFC_HCI_LINK_MGMT_PIPE && pipe != NFC_HCI_ADMIN_PIPE) {
    272		r = nfc_hci_delete_pipe(hdev, pipe);
    273		if (r < 0)
    274			return r;
    275	}
    276
    277	hdev->gate2pipe[gate] = NFC_HCI_INVALID_PIPE;
    278
    279	return 0;
    280}
    281EXPORT_SYMBOL(nfc_hci_disconnect_gate);
    282
    283int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev)
    284{
    285	int r;
    286
    287	r = nfc_hci_clear_all_pipes(hdev);
    288	if (r < 0)
    289		return r;
    290
    291	nfc_hci_reset_pipes(hdev);
    292
    293	return 0;
    294}
    295EXPORT_SYMBOL(nfc_hci_disconnect_all_gates);
    296
    297int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate,
    298			 u8 pipe)
    299{
    300	bool pipe_created = false;
    301	int r;
    302
    303	if (pipe == NFC_HCI_DO_NOT_CREATE_PIPE)
    304		return 0;
    305
    306	if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE)
    307		return -EADDRINUSE;
    308
    309	if (pipe != NFC_HCI_INVALID_PIPE)
    310		goto open_pipe;
    311
    312	switch (dest_gate) {
    313	case NFC_HCI_LINK_MGMT_GATE:
    314		pipe = NFC_HCI_LINK_MGMT_PIPE;
    315		break;
    316	case NFC_HCI_ADMIN_GATE:
    317		pipe = NFC_HCI_ADMIN_PIPE;
    318		break;
    319	default:
    320		pipe = nfc_hci_create_pipe(hdev, dest_host, dest_gate, &r);
    321		if (pipe == NFC_HCI_INVALID_PIPE)
    322			return r;
    323		pipe_created = true;
    324		break;
    325	}
    326
    327open_pipe:
    328	r = nfc_hci_open_pipe(hdev, pipe);
    329	if (r < 0) {
    330		if (pipe_created)
    331			if (nfc_hci_delete_pipe(hdev, pipe) < 0) {
    332				/* TODO: Cannot clean by deleting pipe...
    333				 * -> inconsistent state */
    334			}
    335		return r;
    336	}
    337
    338	hdev->pipes[pipe].gate = dest_gate;
    339	hdev->pipes[pipe].dest_host = dest_host;
    340	hdev->gate2pipe[dest_gate] = pipe;
    341
    342	return 0;
    343}
    344EXPORT_SYMBOL(nfc_hci_connect_gate);