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

qmi_sample_client.c (14521B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Sample in-kernel QMI client driver
      4 *
      5 * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
      6 * Copyright (C) 2017 Linaro Ltd.
      7 */
      8#include <linux/kernel.h>
      9#include <linux/module.h>
     10#include <linux/debugfs.h>
     11#include <linux/device.h>
     12#include <linux/platform_device.h>
     13#include <linux/qrtr.h>
     14#include <linux/net.h>
     15#include <linux/completion.h>
     16#include <linux/idr.h>
     17#include <linux/string.h>
     18#include <net/sock.h>
     19#include <linux/soc/qcom/qmi.h>
     20
     21#define PING_REQ1_TLV_TYPE		0x1
     22#define PING_RESP1_TLV_TYPE		0x2
     23#define PING_OPT1_TLV_TYPE		0x10
     24#define PING_OPT2_TLV_TYPE		0x11
     25
     26#define DATA_REQ1_TLV_TYPE		0x1
     27#define DATA_RESP1_TLV_TYPE		0x2
     28#define DATA_OPT1_TLV_TYPE		0x10
     29#define DATA_OPT2_TLV_TYPE		0x11
     30
     31#define TEST_MED_DATA_SIZE_V01		8192
     32#define TEST_MAX_NAME_SIZE_V01		255
     33
     34#define TEST_PING_REQ_MSG_ID_V01	0x20
     35#define TEST_DATA_REQ_MSG_ID_V01	0x21
     36
     37#define TEST_PING_REQ_MAX_MSG_LEN_V01	266
     38#define TEST_DATA_REQ_MAX_MSG_LEN_V01	8456
     39
     40struct test_name_type_v01 {
     41	u32 name_len;
     42	char name[TEST_MAX_NAME_SIZE_V01];
     43};
     44
     45static struct qmi_elem_info test_name_type_v01_ei[] = {
     46	{
     47		.data_type	= QMI_DATA_LEN,
     48		.elem_len	= 1,
     49		.elem_size	= sizeof(u8),
     50		.array_type	= NO_ARRAY,
     51		.tlv_type	= QMI_COMMON_TLV_TYPE,
     52		.offset		= offsetof(struct test_name_type_v01,
     53					   name_len),
     54	},
     55	{
     56		.data_type	= QMI_UNSIGNED_1_BYTE,
     57		.elem_len	= TEST_MAX_NAME_SIZE_V01,
     58		.elem_size	= sizeof(char),
     59		.array_type	= VAR_LEN_ARRAY,
     60		.tlv_type	= QMI_COMMON_TLV_TYPE,
     61		.offset		= offsetof(struct test_name_type_v01,
     62					   name),
     63	},
     64	{}
     65};
     66
     67struct test_ping_req_msg_v01 {
     68	char ping[4];
     69
     70	u8 client_name_valid;
     71	struct test_name_type_v01 client_name;
     72};
     73
     74static struct qmi_elem_info test_ping_req_msg_v01_ei[] = {
     75	{
     76		.data_type	= QMI_UNSIGNED_1_BYTE,
     77		.elem_len	= 4,
     78		.elem_size	= sizeof(char),
     79		.array_type	= STATIC_ARRAY,
     80		.tlv_type	= PING_REQ1_TLV_TYPE,
     81		.offset		= offsetof(struct test_ping_req_msg_v01,
     82					   ping),
     83	},
     84	{
     85		.data_type	= QMI_OPT_FLAG,
     86		.elem_len	= 1,
     87		.elem_size	= sizeof(u8),
     88		.array_type	= NO_ARRAY,
     89		.tlv_type	= PING_OPT1_TLV_TYPE,
     90		.offset		= offsetof(struct test_ping_req_msg_v01,
     91					   client_name_valid),
     92	},
     93	{
     94		.data_type	= QMI_STRUCT,
     95		.elem_len	= 1,
     96		.elem_size	= sizeof(struct test_name_type_v01),
     97		.array_type	= NO_ARRAY,
     98		.tlv_type	= PING_OPT1_TLV_TYPE,
     99		.offset		= offsetof(struct test_ping_req_msg_v01,
    100					   client_name),
    101		.ei_array	= test_name_type_v01_ei,
    102	},
    103	{}
    104};
    105
    106struct test_ping_resp_msg_v01 {
    107	struct qmi_response_type_v01 resp;
    108
    109	u8 pong_valid;
    110	char pong[4];
    111
    112	u8 service_name_valid;
    113	struct test_name_type_v01 service_name;
    114};
    115
    116static struct qmi_elem_info test_ping_resp_msg_v01_ei[] = {
    117	{
    118		.data_type	= QMI_STRUCT,
    119		.elem_len	= 1,
    120		.elem_size	= sizeof(struct qmi_response_type_v01),
    121		.array_type	= NO_ARRAY,
    122		.tlv_type	= PING_RESP1_TLV_TYPE,
    123		.offset		= offsetof(struct test_ping_resp_msg_v01,
    124					   resp),
    125		.ei_array	= qmi_response_type_v01_ei,
    126	},
    127	{
    128		.data_type	= QMI_OPT_FLAG,
    129		.elem_len	= 1,
    130		.elem_size	= sizeof(u8),
    131		.array_type	= NO_ARRAY,
    132		.tlv_type	= PING_OPT1_TLV_TYPE,
    133		.offset		= offsetof(struct test_ping_resp_msg_v01,
    134					   pong_valid),
    135	},
    136	{
    137		.data_type	= QMI_UNSIGNED_1_BYTE,
    138		.elem_len	= 4,
    139		.elem_size	= sizeof(char),
    140		.array_type	= STATIC_ARRAY,
    141		.tlv_type	= PING_OPT1_TLV_TYPE,
    142		.offset		= offsetof(struct test_ping_resp_msg_v01,
    143					   pong),
    144	},
    145	{
    146		.data_type	= QMI_OPT_FLAG,
    147		.elem_len	= 1,
    148		.elem_size	= sizeof(u8),
    149		.array_type	= NO_ARRAY,
    150		.tlv_type	= PING_OPT2_TLV_TYPE,
    151		.offset		= offsetof(struct test_ping_resp_msg_v01,
    152					   service_name_valid),
    153	},
    154	{
    155		.data_type	= QMI_STRUCT,
    156		.elem_len	= 1,
    157		.elem_size	= sizeof(struct test_name_type_v01),
    158		.array_type	= NO_ARRAY,
    159		.tlv_type	= PING_OPT2_TLV_TYPE,
    160		.offset		= offsetof(struct test_ping_resp_msg_v01,
    161					   service_name),
    162		.ei_array	= test_name_type_v01_ei,
    163	},
    164	{}
    165};
    166
    167struct test_data_req_msg_v01 {
    168	u32 data_len;
    169	u8 data[TEST_MED_DATA_SIZE_V01];
    170
    171	u8 client_name_valid;
    172	struct test_name_type_v01 client_name;
    173};
    174
    175static struct qmi_elem_info test_data_req_msg_v01_ei[] = {
    176	{
    177		.data_type	= QMI_DATA_LEN,
    178		.elem_len	= 1,
    179		.elem_size	= sizeof(u32),
    180		.array_type	= NO_ARRAY,
    181		.tlv_type	= DATA_REQ1_TLV_TYPE,
    182		.offset		= offsetof(struct test_data_req_msg_v01,
    183					   data_len),
    184	},
    185	{
    186		.data_type	= QMI_UNSIGNED_1_BYTE,
    187		.elem_len	= TEST_MED_DATA_SIZE_V01,
    188		.elem_size	= sizeof(u8),
    189		.array_type	= VAR_LEN_ARRAY,
    190		.tlv_type	= DATA_REQ1_TLV_TYPE,
    191		.offset		= offsetof(struct test_data_req_msg_v01,
    192					   data),
    193	},
    194	{
    195		.data_type	= QMI_OPT_FLAG,
    196		.elem_len	= 1,
    197		.elem_size	= sizeof(u8),
    198		.array_type	= NO_ARRAY,
    199		.tlv_type	= DATA_OPT1_TLV_TYPE,
    200		.offset		= offsetof(struct test_data_req_msg_v01,
    201					   client_name_valid),
    202	},
    203	{
    204		.data_type	= QMI_STRUCT,
    205		.elem_len	= 1,
    206		.elem_size	= sizeof(struct test_name_type_v01),
    207		.array_type	= NO_ARRAY,
    208		.tlv_type	= DATA_OPT1_TLV_TYPE,
    209		.offset		= offsetof(struct test_data_req_msg_v01,
    210					   client_name),
    211		.ei_array	= test_name_type_v01_ei,
    212	},
    213	{}
    214};
    215
    216struct test_data_resp_msg_v01 {
    217	struct qmi_response_type_v01 resp;
    218
    219	u8 data_valid;
    220	u32 data_len;
    221	u8 data[TEST_MED_DATA_SIZE_V01];
    222
    223	u8 service_name_valid;
    224	struct test_name_type_v01 service_name;
    225};
    226
    227static struct qmi_elem_info test_data_resp_msg_v01_ei[] = {
    228	{
    229		.data_type	= QMI_STRUCT,
    230		.elem_len	= 1,
    231		.elem_size	= sizeof(struct qmi_response_type_v01),
    232		.array_type	= NO_ARRAY,
    233		.tlv_type	= DATA_RESP1_TLV_TYPE,
    234		.offset		= offsetof(struct test_data_resp_msg_v01,
    235					   resp),
    236		.ei_array	= qmi_response_type_v01_ei,
    237	},
    238	{
    239		.data_type	= QMI_OPT_FLAG,
    240		.elem_len	= 1,
    241		.elem_size	= sizeof(u8),
    242		.array_type	= NO_ARRAY,
    243		.tlv_type	= DATA_OPT1_TLV_TYPE,
    244		.offset		= offsetof(struct test_data_resp_msg_v01,
    245					   data_valid),
    246	},
    247	{
    248		.data_type	= QMI_DATA_LEN,
    249		.elem_len	= 1,
    250		.elem_size	= sizeof(u32),
    251		.array_type	= NO_ARRAY,
    252		.tlv_type	= DATA_OPT1_TLV_TYPE,
    253		.offset		= offsetof(struct test_data_resp_msg_v01,
    254					   data_len),
    255	},
    256	{
    257		.data_type	= QMI_UNSIGNED_1_BYTE,
    258		.elem_len	= TEST_MED_DATA_SIZE_V01,
    259		.elem_size	= sizeof(u8),
    260		.array_type	= VAR_LEN_ARRAY,
    261		.tlv_type	= DATA_OPT1_TLV_TYPE,
    262		.offset		= offsetof(struct test_data_resp_msg_v01,
    263					   data),
    264	},
    265	{
    266		.data_type	= QMI_OPT_FLAG,
    267		.elem_len	= 1,
    268		.elem_size	= sizeof(u8),
    269		.array_type	= NO_ARRAY,
    270		.tlv_type	= DATA_OPT2_TLV_TYPE,
    271		.offset		= offsetof(struct test_data_resp_msg_v01,
    272					   service_name_valid),
    273	},
    274	{
    275		.data_type	= QMI_STRUCT,
    276		.elem_len	= 1,
    277		.elem_size	= sizeof(struct test_name_type_v01),
    278		.array_type	= NO_ARRAY,
    279		.tlv_type	= DATA_OPT2_TLV_TYPE,
    280		.offset		= offsetof(struct test_data_resp_msg_v01,
    281					   service_name),
    282		.ei_array	= test_name_type_v01_ei,
    283	},
    284	{}
    285};
    286
    287/*
    288 * ping_write() - ping_pong debugfs file write handler
    289 * @file:	debugfs file context
    290 * @user_buf:	reference to the user data (ignored)
    291 * @count:	number of bytes in @user_buf
    292 * @ppos:	offset in @file to write
    293 *
    294 * This function allows user space to send out a ping_pong QMI encoded message
    295 * to the associated remote test service and will return with the result of the
    296 * transaction. It serves as an example of how to provide a custom response
    297 * handler.
    298 *
    299 * Return: @count, or negative errno on failure.
    300 */
    301static ssize_t ping_write(struct file *file, const char __user *user_buf,
    302			  size_t count, loff_t *ppos)
    303{
    304	struct qmi_handle *qmi = file->private_data;
    305	struct test_ping_req_msg_v01 req = {};
    306	struct qmi_txn txn;
    307	int ret;
    308
    309	memcpy(req.ping, "ping", sizeof(req.ping));
    310
    311	ret = qmi_txn_init(qmi, &txn, NULL, NULL);
    312	if (ret < 0)
    313		return ret;
    314
    315	ret = qmi_send_request(qmi, NULL, &txn,
    316			       TEST_PING_REQ_MSG_ID_V01,
    317			       TEST_PING_REQ_MAX_MSG_LEN_V01,
    318			       test_ping_req_msg_v01_ei, &req);
    319	if (ret < 0) {
    320		qmi_txn_cancel(&txn);
    321		return ret;
    322	}
    323
    324	ret = qmi_txn_wait(&txn, 5 * HZ);
    325	if (ret < 0)
    326		count = ret;
    327
    328	return count;
    329}
    330
    331static const struct file_operations ping_fops = {
    332	.open = simple_open,
    333	.write = ping_write,
    334};
    335
    336static void ping_pong_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
    337			 struct qmi_txn *txn, const void *data)
    338{
    339	const struct test_ping_resp_msg_v01 *resp = data;
    340
    341	if (!txn) {
    342		pr_err("spurious ping response\n");
    343		return;
    344	}
    345
    346	if (resp->resp.result == QMI_RESULT_FAILURE_V01)
    347		txn->result = -ENXIO;
    348	else if (!resp->pong_valid || memcmp(resp->pong, "pong", 4))
    349		txn->result = -EINVAL;
    350
    351	complete(&txn->completion);
    352}
    353
    354/*
    355 * data_write() - data debugfs file write handler
    356 * @file:	debugfs file context
    357 * @user_buf:	reference to the user data
    358 * @count:	number of bytes in @user_buf
    359 * @ppos:	offset in @file to write
    360 *
    361 * This function allows user space to send out a data QMI encoded message to
    362 * the associated remote test service and will return with the result of the
    363 * transaction. It serves as an example of how to have the QMI helpers decode a
    364 * transaction response into a provided object automatically.
    365 *
    366 * Return: @count, or negative errno on failure.
    367 */
    368static ssize_t data_write(struct file *file, const char __user *user_buf,
    369			  size_t count, loff_t *ppos)
    370
    371{
    372	struct qmi_handle *qmi = file->private_data;
    373	struct test_data_resp_msg_v01 *resp;
    374	struct test_data_req_msg_v01 *req;
    375	struct qmi_txn txn;
    376	int ret;
    377
    378	req = kzalloc(sizeof(*req), GFP_KERNEL);
    379	if (!req)
    380		return -ENOMEM;
    381
    382	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
    383	if (!resp) {
    384		kfree(req);
    385		return -ENOMEM;
    386	}
    387
    388	req->data_len = min_t(size_t, sizeof(req->data), count);
    389	if (copy_from_user(req->data, user_buf, req->data_len)) {
    390		ret = -EFAULT;
    391		goto out;
    392	}
    393
    394	ret = qmi_txn_init(qmi, &txn, test_data_resp_msg_v01_ei, resp);
    395	if (ret < 0)
    396		goto out;
    397
    398	ret = qmi_send_request(qmi, NULL, &txn,
    399			       TEST_DATA_REQ_MSG_ID_V01,
    400			       TEST_DATA_REQ_MAX_MSG_LEN_V01,
    401			       test_data_req_msg_v01_ei, req);
    402	if (ret < 0) {
    403		qmi_txn_cancel(&txn);
    404		goto out;
    405	}
    406
    407	ret = qmi_txn_wait(&txn, 5 * HZ);
    408	if (ret < 0) {
    409		goto out;
    410	} else if (!resp->data_valid ||
    411		   resp->data_len != req->data_len ||
    412		   memcmp(resp->data, req->data, req->data_len)) {
    413		pr_err("response data doesn't match expectation\n");
    414		ret = -EINVAL;
    415		goto out;
    416	}
    417
    418	ret = count;
    419
    420out:
    421	kfree(resp);
    422	kfree(req);
    423
    424	return ret;
    425}
    426
    427static const struct file_operations data_fops = {
    428	.open = simple_open,
    429	.write = data_write,
    430};
    431
    432static const struct qmi_msg_handler qmi_sample_handlers[] = {
    433	{
    434		.type = QMI_RESPONSE,
    435		.msg_id = TEST_PING_REQ_MSG_ID_V01,
    436		.ei = test_ping_resp_msg_v01_ei,
    437		.decoded_size = sizeof(struct test_ping_req_msg_v01),
    438		.fn = ping_pong_cb
    439	},
    440	{}
    441};
    442
    443struct qmi_sample {
    444	struct qmi_handle qmi;
    445
    446	struct dentry *de_dir;
    447	struct dentry *de_data;
    448	struct dentry *de_ping;
    449};
    450
    451static struct dentry *qmi_debug_dir;
    452
    453static int qmi_sample_probe(struct platform_device *pdev)
    454{
    455	struct sockaddr_qrtr *sq;
    456	struct qmi_sample *sample;
    457	char path[20];
    458	int ret;
    459
    460	sample = devm_kzalloc(&pdev->dev, sizeof(*sample), GFP_KERNEL);
    461	if (!sample)
    462		return -ENOMEM;
    463
    464	ret = qmi_handle_init(&sample->qmi, TEST_DATA_REQ_MAX_MSG_LEN_V01,
    465			      NULL,
    466			      qmi_sample_handlers);
    467	if (ret < 0)
    468		return ret;
    469
    470	sq = dev_get_platdata(&pdev->dev);
    471	ret = kernel_connect(sample->qmi.sock, (struct sockaddr *)sq,
    472			     sizeof(*sq), 0);
    473	if (ret < 0) {
    474		pr_err("failed to connect to remote service port\n");
    475		goto err_release_qmi_handle;
    476	}
    477
    478	snprintf(path, sizeof(path), "%d:%d", sq->sq_node, sq->sq_port);
    479
    480	sample->de_dir = debugfs_create_dir(path, qmi_debug_dir);
    481	if (IS_ERR(sample->de_dir)) {
    482		ret = PTR_ERR(sample->de_dir);
    483		goto err_release_qmi_handle;
    484	}
    485
    486	sample->de_data = debugfs_create_file("data", 0600, sample->de_dir,
    487					      sample, &data_fops);
    488	if (IS_ERR(sample->de_data)) {
    489		ret = PTR_ERR(sample->de_data);
    490		goto err_remove_de_dir;
    491	}
    492
    493	sample->de_ping = debugfs_create_file("ping", 0600, sample->de_dir,
    494					      sample, &ping_fops);
    495	if (IS_ERR(sample->de_ping)) {
    496		ret = PTR_ERR(sample->de_ping);
    497		goto err_remove_de_data;
    498	}
    499
    500	platform_set_drvdata(pdev, sample);
    501
    502	return 0;
    503
    504err_remove_de_data:
    505	debugfs_remove(sample->de_data);
    506err_remove_de_dir:
    507	debugfs_remove(sample->de_dir);
    508err_release_qmi_handle:
    509	qmi_handle_release(&sample->qmi);
    510
    511	return ret;
    512}
    513
    514static int qmi_sample_remove(struct platform_device *pdev)
    515{
    516	struct qmi_sample *sample = platform_get_drvdata(pdev);
    517
    518	debugfs_remove(sample->de_ping);
    519	debugfs_remove(sample->de_data);
    520	debugfs_remove(sample->de_dir);
    521
    522	qmi_handle_release(&sample->qmi);
    523
    524	return 0;
    525}
    526
    527static struct platform_driver qmi_sample_driver = {
    528	.probe = qmi_sample_probe,
    529	.remove = qmi_sample_remove,
    530	.driver = {
    531		.name = "qmi_sample_client",
    532	},
    533};
    534
    535static int qmi_sample_new_server(struct qmi_handle *qmi,
    536				 struct qmi_service *service)
    537{
    538	struct platform_device *pdev;
    539	struct sockaddr_qrtr sq = { AF_QIPCRTR, service->node, service->port };
    540	int ret;
    541
    542	pdev = platform_device_alloc("qmi_sample_client", PLATFORM_DEVID_AUTO);
    543	if (!pdev)
    544		return -ENOMEM;
    545
    546	ret = platform_device_add_data(pdev, &sq, sizeof(sq));
    547	if (ret)
    548		goto err_put_device;
    549
    550	ret = platform_device_add(pdev);
    551	if (ret)
    552		goto err_put_device;
    553
    554	service->priv = pdev;
    555
    556	return 0;
    557
    558err_put_device:
    559	platform_device_put(pdev);
    560
    561	return ret;
    562}
    563
    564static void qmi_sample_del_server(struct qmi_handle *qmi,
    565				  struct qmi_service *service)
    566{
    567	struct platform_device *pdev = service->priv;
    568
    569	platform_device_unregister(pdev);
    570}
    571
    572static struct qmi_handle lookup_client;
    573
    574static const struct qmi_ops lookup_ops = {
    575	.new_server = qmi_sample_new_server,
    576	.del_server = qmi_sample_del_server,
    577};
    578
    579static int qmi_sample_init(void)
    580{
    581	int ret;
    582
    583	qmi_debug_dir = debugfs_create_dir("qmi_sample", NULL);
    584	if (IS_ERR(qmi_debug_dir)) {
    585		pr_err("failed to create qmi_sample dir\n");
    586		return PTR_ERR(qmi_debug_dir);
    587	}
    588
    589	ret = platform_driver_register(&qmi_sample_driver);
    590	if (ret)
    591		goto err_remove_debug_dir;
    592
    593	ret = qmi_handle_init(&lookup_client, 0, &lookup_ops, NULL);
    594	if (ret < 0)
    595		goto err_unregister_driver;
    596
    597	qmi_add_lookup(&lookup_client, 15, 0, 0);
    598
    599	return 0;
    600
    601err_unregister_driver:
    602	platform_driver_unregister(&qmi_sample_driver);
    603err_remove_debug_dir:
    604	debugfs_remove(qmi_debug_dir);
    605
    606	return ret;
    607}
    608
    609static void qmi_sample_exit(void)
    610{
    611	qmi_handle_release(&lookup_client);
    612
    613	platform_driver_unregister(&qmi_sample_driver);
    614
    615	debugfs_remove(qmi_debug_dir);
    616}
    617
    618module_init(qmi_sample_init);
    619module_exit(qmi_sample_exit);
    620
    621MODULE_DESCRIPTION("Sample QMI client driver");
    622MODULE_LICENSE("GPL v2");