162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2021 Samsung Electrnoics
462306a36Sopenharmony_ci * Bongsu Jeon <bongsu.jeon@samsung.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Test code for nci
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <stdlib.h>
1062306a36Sopenharmony_ci#include <errno.h>
1162306a36Sopenharmony_ci#include <string.h>
1262306a36Sopenharmony_ci#include <sys/ioctl.h>
1362306a36Sopenharmony_ci#include <fcntl.h>
1462306a36Sopenharmony_ci#include <pthread.h>
1562306a36Sopenharmony_ci#include <linux/genetlink.h>
1662306a36Sopenharmony_ci#include <sys/socket.h>
1762306a36Sopenharmony_ci#include <linux/nfc.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "../kselftest_harness.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define GENLMSG_DATA(glh)	((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
2262306a36Sopenharmony_ci#define GENLMSG_PAYLOAD(glh)	(NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
2362306a36Sopenharmony_ci#define NLA_DATA(na)		((void *)((char *)(na) + NLA_HDRLEN))
2462306a36Sopenharmony_ci#define NLA_PAYLOAD(len)	((len) - NLA_HDRLEN)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define MAX_MSG_SIZE	1024
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define IOCTL_GET_NCIDEV_IDX	0
2962306a36Sopenharmony_ci#define VIRTUAL_NFC_PROTOCOLS	(NFC_PROTO_JEWEL_MASK | \
3062306a36Sopenharmony_ci				 NFC_PROTO_MIFARE_MASK | \
3162306a36Sopenharmony_ci				 NFC_PROTO_FELICA_MASK | \
3262306a36Sopenharmony_ci				 NFC_PROTO_ISO14443_MASK | \
3362306a36Sopenharmony_ci				 NFC_PROTO_ISO14443_B_MASK | \
3462306a36Sopenharmony_ci				 NFC_PROTO_ISO15693_MASK)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciconst __u8 nci_reset_cmd[] = {0x20, 0x00, 0x01, 0x01};
3762306a36Sopenharmony_ciconst __u8 nci_init_cmd[] = {0x20, 0x01, 0x00};
3862306a36Sopenharmony_ciconst __u8 nci_rf_discovery_cmd[] = {0x21, 0x03, 0x09, 0x04, 0x00, 0x01,
3962306a36Sopenharmony_ci				      0x01, 0x01, 0x02, 0x01, 0x06, 0x01};
4062306a36Sopenharmony_ciconst __u8 nci_init_cmd_v2[] = {0x20, 0x01, 0x02, 0x00, 0x00};
4162306a36Sopenharmony_ciconst __u8 nci_rf_disc_map_cmd[] = {0x21, 0x00, 0x07, 0x02, 0x04, 0x03,
4262306a36Sopenharmony_ci				     0x02, 0x05, 0x03, 0x03};
4362306a36Sopenharmony_ciconst __u8 nci_rf_deact_cmd[] = {0x21, 0x06, 0x01, 0x00};
4462306a36Sopenharmony_ciconst __u8 nci_reset_rsp[] = {0x40, 0x00, 0x03, 0x00, 0x10, 0x01};
4562306a36Sopenharmony_ciconst __u8 nci_reset_rsp_v2[] = {0x40, 0x00, 0x01, 0x00};
4662306a36Sopenharmony_ciconst __u8 nci_reset_ntf[] = {0x60, 0x00, 0x09, 0x02, 0x01, 0x20, 0x0e,
4762306a36Sopenharmony_ci			       0x04, 0x61, 0x00, 0x04, 0x02};
4862306a36Sopenharmony_ciconst __u8 nci_init_rsp[] = {0x40, 0x01, 0x14, 0x00, 0x02, 0x0e, 0x02,
4962306a36Sopenharmony_ci			      0x00, 0x03, 0x01, 0x02, 0x03, 0x02, 0xc8,
5062306a36Sopenharmony_ci			      0x00, 0xff, 0x10, 0x00, 0x0e, 0x12, 0x00,
5162306a36Sopenharmony_ci			      0x00, 0x04};
5262306a36Sopenharmony_ciconst __u8 nci_init_rsp_v2[] = {0x40, 0x01, 0x1c, 0x00, 0x1a, 0x7e, 0x06,
5362306a36Sopenharmony_ci				 0x00, 0x02, 0x92, 0x04, 0xff, 0xff, 0x01,
5462306a36Sopenharmony_ci				 0x00, 0x40, 0x06, 0x00, 0x00, 0x01, 0x01,
5562306a36Sopenharmony_ci				 0x00, 0x02, 0x00, 0x03, 0x01, 0x01, 0x06,
5662306a36Sopenharmony_ci				 0x00, 0x80, 0x00};
5762306a36Sopenharmony_ciconst __u8 nci_rf_disc_map_rsp[] = {0x41, 0x00, 0x01, 0x00};
5862306a36Sopenharmony_ciconst __u8 nci_rf_disc_rsp[] = {0x41, 0x03, 0x01, 0x00};
5962306a36Sopenharmony_ciconst __u8 nci_rf_deact_rsp[] = {0x41, 0x06, 0x01, 0x00};
6062306a36Sopenharmony_ciconst __u8 nci_rf_deact_ntf[] = {0x61, 0x06, 0x02, 0x00, 0x00};
6162306a36Sopenharmony_ciconst __u8 nci_rf_activate_ntf[] = {0x61, 0x05, 0x1D, 0x01, 0x02, 0x04, 0x00,
6262306a36Sopenharmony_ci				     0xFF, 0xFF, 0x0C, 0x44, 0x03, 0x07, 0x04,
6362306a36Sopenharmony_ci				     0x62, 0x26, 0x11, 0x80, 0x1D, 0x80, 0x01,
6462306a36Sopenharmony_ci				     0x20, 0x00, 0x00, 0x00, 0x06, 0x05, 0x75,
6562306a36Sopenharmony_ci				     0x77, 0x81, 0x02, 0x80};
6662306a36Sopenharmony_ciconst __u8 nci_t4t_select_cmd[] = {0x00, 0x00, 0x0C, 0x00, 0xA4, 0x04, 0x00,
6762306a36Sopenharmony_ci				    0x07, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};
6862306a36Sopenharmony_ciconst __u8 nci_t4t_select_cmd2[] = {0x00, 0x00, 0x07, 0x00, 0xA4, 0x00, 0x0C, 0x02,
6962306a36Sopenharmony_ci				     0xE1, 0x03};
7062306a36Sopenharmony_ciconst __u8 nci_t4t_select_cmd3[] = {0x00, 0x00, 0x07, 0x00, 0xA4, 0x00, 0x0C, 0x02,
7162306a36Sopenharmony_ci				     0xE1, 0x04};
7262306a36Sopenharmony_ciconst __u8 nci_t4t_read_cmd[] = {0x00, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x00, 0x0F};
7362306a36Sopenharmony_ciconst __u8 nci_t4t_read_rsp[] = {0x00, 0x00, 0x11, 0x00, 0x0F, 0x20, 0x00, 0x3B,
7462306a36Sopenharmony_ci				  0x00, 0x34, 0x04, 0x06, 0xE1, 0x04, 0x08, 0x00,
7562306a36Sopenharmony_ci				  0x00, 0x00, 0x90, 0x00};
7662306a36Sopenharmony_ciconst __u8 nci_t4t_read_cmd2[] = {0x00, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x00, 0x02};
7762306a36Sopenharmony_ciconst __u8 nci_t4t_read_rsp2[] = {0x00, 0x00, 0x04, 0x00, 0x0F, 0x90, 0x00};
7862306a36Sopenharmony_ciconst __u8 nci_t4t_read_cmd3[] = {0x00, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x02, 0x0F};
7962306a36Sopenharmony_ciconst __u8 nci_t4t_read_rsp3[] = {0x00, 0x00, 0x11, 0xD1, 0x01, 0x0B, 0x54, 0x02,
8062306a36Sopenharmony_ci				   0x65, 0x6E, 0x4E, 0x46, 0x43, 0x20, 0x54, 0x45,
8162306a36Sopenharmony_ci				   0x53, 0x54, 0x90, 0x00};
8262306a36Sopenharmony_ciconst __u8 nci_t4t_rsp_ok[] = {0x00, 0x00, 0x02, 0x90, 0x00};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistruct msgtemplate {
8562306a36Sopenharmony_ci	struct nlmsghdr n;
8662306a36Sopenharmony_ci	struct genlmsghdr g;
8762306a36Sopenharmony_ci	char buf[MAX_MSG_SIZE];
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int create_nl_socket(void)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	int fd;
9362306a36Sopenharmony_ci	struct sockaddr_nl local;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
9662306a36Sopenharmony_ci	if (fd < 0)
9762306a36Sopenharmony_ci		return -1;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	memset(&local, 0, sizeof(local));
10062306a36Sopenharmony_ci	local.nl_family = AF_NETLINK;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0)
10362306a36Sopenharmony_ci		goto error;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	return fd;
10662306a36Sopenharmony_cierror:
10762306a36Sopenharmony_ci	close(fd);
10862306a36Sopenharmony_ci	return -1;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int send_cmd_mt_nla(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
11262306a36Sopenharmony_ci			   __u8 genl_cmd, int nla_num, __u16 nla_type[],
11362306a36Sopenharmony_ci			   void *nla_data[], int nla_len[], __u16 flags)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct sockaddr_nl nladdr;
11662306a36Sopenharmony_ci	struct msgtemplate msg;
11762306a36Sopenharmony_ci	struct nlattr *na;
11862306a36Sopenharmony_ci	int cnt, prv_len;
11962306a36Sopenharmony_ci	int r, buflen;
12062306a36Sopenharmony_ci	char *buf;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
12362306a36Sopenharmony_ci	msg.n.nlmsg_type = nlmsg_type;
12462306a36Sopenharmony_ci	msg.n.nlmsg_flags = flags;
12562306a36Sopenharmony_ci	msg.n.nlmsg_seq = 0;
12662306a36Sopenharmony_ci	msg.n.nlmsg_pid = nlmsg_pid;
12762306a36Sopenharmony_ci	msg.g.cmd = genl_cmd;
12862306a36Sopenharmony_ci	msg.g.version = 0x1;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	prv_len = 0;
13162306a36Sopenharmony_ci	for (cnt = 0; cnt < nla_num; cnt++) {
13262306a36Sopenharmony_ci		na = (struct nlattr *)(GENLMSG_DATA(&msg) + prv_len);
13362306a36Sopenharmony_ci		na->nla_type = nla_type[cnt];
13462306a36Sopenharmony_ci		na->nla_len = nla_len[cnt] + NLA_HDRLEN;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		if (nla_len[cnt] > 0)
13762306a36Sopenharmony_ci			memcpy(NLA_DATA(na), nla_data[cnt], nla_len[cnt]);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		prv_len = NLA_ALIGN(nla_len[cnt]) + NLA_HDRLEN;
14062306a36Sopenharmony_ci		msg.n.nlmsg_len += prv_len;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	buf = (char *)&msg;
14462306a36Sopenharmony_ci	buflen = msg.n.nlmsg_len;
14562306a36Sopenharmony_ci	memset(&nladdr, 0, sizeof(nladdr));
14662306a36Sopenharmony_ci	nladdr.nl_family = AF_NETLINK;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *)&nladdr,
14962306a36Sopenharmony_ci			   sizeof(nladdr))) < buflen) {
15062306a36Sopenharmony_ci		if (r > 0) {
15162306a36Sopenharmony_ci			buf += r;
15262306a36Sopenharmony_ci			buflen -= r;
15362306a36Sopenharmony_ci		} else if (errno != EAGAIN) {
15462306a36Sopenharmony_ci			return -1;
15562306a36Sopenharmony_ci		}
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci	return 0;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int send_get_nfc_family(int sd, __u32 pid)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	__u16 nla_get_family_type = CTRL_ATTR_FAMILY_NAME;
16362306a36Sopenharmony_ci	void *nla_get_family_data;
16462306a36Sopenharmony_ci	int nla_get_family_len;
16562306a36Sopenharmony_ci	char family_name[100];
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	nla_get_family_len = strlen(NFC_GENL_NAME) + 1;
16862306a36Sopenharmony_ci	strcpy(family_name, NFC_GENL_NAME);
16962306a36Sopenharmony_ci	nla_get_family_data = family_name;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return send_cmd_mt_nla(sd, GENL_ID_CTRL, pid, CTRL_CMD_GETFAMILY,
17262306a36Sopenharmony_ci				1, &nla_get_family_type, &nla_get_family_data,
17362306a36Sopenharmony_ci				&nla_get_family_len, NLM_F_REQUEST);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic int get_family_id(int sd, __u32 pid, __u32 *event_group)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct {
17962306a36Sopenharmony_ci		struct nlmsghdr n;
18062306a36Sopenharmony_ci		struct genlmsghdr g;
18162306a36Sopenharmony_ci		char buf[512];
18262306a36Sopenharmony_ci	} ans;
18362306a36Sopenharmony_ci	struct nlattr *na;
18462306a36Sopenharmony_ci	int resp_len;
18562306a36Sopenharmony_ci	__u16 id;
18662306a36Sopenharmony_ci	int len;
18762306a36Sopenharmony_ci	int rc;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	rc = send_get_nfc_family(sd, pid);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (rc < 0)
19262306a36Sopenharmony_ci		return 0;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	resp_len = recv(sd, &ans, sizeof(ans), 0);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (ans.n.nlmsg_type == NLMSG_ERROR || resp_len < 0 ||
19762306a36Sopenharmony_ci	    !NLMSG_OK(&ans.n, resp_len))
19862306a36Sopenharmony_ci		return 0;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	len = 0;
20162306a36Sopenharmony_ci	resp_len = GENLMSG_PAYLOAD(&ans.n);
20262306a36Sopenharmony_ci	na = (struct nlattr *)GENLMSG_DATA(&ans);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	while (len < resp_len) {
20562306a36Sopenharmony_ci		len += NLA_ALIGN(na->nla_len);
20662306a36Sopenharmony_ci		if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
20762306a36Sopenharmony_ci			id = *(__u16 *)NLA_DATA(na);
20862306a36Sopenharmony_ci		} else if (na->nla_type == CTRL_ATTR_MCAST_GROUPS) {
20962306a36Sopenharmony_ci			struct nlattr *nested_na;
21062306a36Sopenharmony_ci			struct nlattr *group_na;
21162306a36Sopenharmony_ci			int group_attr_len;
21262306a36Sopenharmony_ci			int group_attr;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci			nested_na = (struct nlattr *)((char *)na + NLA_HDRLEN);
21562306a36Sopenharmony_ci			group_na = (struct nlattr *)((char *)nested_na + NLA_HDRLEN);
21662306a36Sopenharmony_ci			group_attr_len = 0;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci			for (group_attr = CTRL_ATTR_MCAST_GRP_UNSPEC;
21962306a36Sopenharmony_ci				group_attr < CTRL_ATTR_MCAST_GRP_MAX; group_attr++) {
22062306a36Sopenharmony_ci				if (group_na->nla_type == CTRL_ATTR_MCAST_GRP_ID) {
22162306a36Sopenharmony_ci					*event_group = *(__u32 *)((char *)group_na +
22262306a36Sopenharmony_ci								  NLA_HDRLEN);
22362306a36Sopenharmony_ci					break;
22462306a36Sopenharmony_ci				}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci				group_attr_len += NLA_ALIGN(group_na->nla_len) +
22762306a36Sopenharmony_ci						  NLA_HDRLEN;
22862306a36Sopenharmony_ci				if (group_attr_len >= nested_na->nla_len)
22962306a36Sopenharmony_ci					break;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci				group_na = (struct nlattr *)((char *)group_na +
23262306a36Sopenharmony_ci							     NLA_ALIGN(group_na->nla_len));
23362306a36Sopenharmony_ci			}
23462306a36Sopenharmony_ci		}
23562306a36Sopenharmony_ci		na = (struct nlattr *)(GENLMSG_DATA(&ans) + len);
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci	return id;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic int send_cmd_with_idx(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
24162306a36Sopenharmony_ci			     __u8 genl_cmd, int dev_id)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	__u16 nla_type = NFC_ATTR_DEVICE_INDEX;
24462306a36Sopenharmony_ci	void *nla_data = &dev_id;
24562306a36Sopenharmony_ci	int nla_len = 4;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	return send_cmd_mt_nla(sd, nlmsg_type, nlmsg_pid, genl_cmd, 1,
24862306a36Sopenharmony_ci				&nla_type, &nla_data, &nla_len, NLM_F_REQUEST);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int get_nci_devid(int sd, __u16 fid, __u32 pid, int dev_id, struct msgtemplate *msg)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	int rc, resp_len;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	rc = send_cmd_with_idx(sd, fid, pid, NFC_CMD_GET_DEVICE, dev_id);
25662306a36Sopenharmony_ci	if (rc < 0) {
25762306a36Sopenharmony_ci		rc = -1;
25862306a36Sopenharmony_ci		goto error;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	resp_len = recv(sd, msg, sizeof(*msg), 0);
26262306a36Sopenharmony_ci	if (resp_len < 0) {
26362306a36Sopenharmony_ci		rc = -2;
26462306a36Sopenharmony_ci		goto error;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (msg->n.nlmsg_type == NLMSG_ERROR ||
26862306a36Sopenharmony_ci	    !NLMSG_OK(&msg->n, resp_len)) {
26962306a36Sopenharmony_ci		rc = -3;
27062306a36Sopenharmony_ci		goto error;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return 0;
27462306a36Sopenharmony_cierror:
27562306a36Sopenharmony_ci	return rc;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic __u8 get_dev_enable_state(struct msgtemplate *msg)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct nlattr *na;
28162306a36Sopenharmony_ci	int resp_len;
28262306a36Sopenharmony_ci	int len;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	resp_len = GENLMSG_PAYLOAD(&msg->n);
28562306a36Sopenharmony_ci	na = (struct nlattr *)GENLMSG_DATA(msg);
28662306a36Sopenharmony_ci	len = 0;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	while (len < resp_len) {
28962306a36Sopenharmony_ci		len += NLA_ALIGN(na->nla_len);
29062306a36Sopenharmony_ci		if (na->nla_type == NFC_ATTR_DEVICE_POWERED)
29162306a36Sopenharmony_ci			return *(char *)NLA_DATA(na);
29262306a36Sopenharmony_ci		na = (struct nlattr *)(GENLMSG_DATA(msg) + len);
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	return resp_len;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ciFIXTURE(NCI) {
29962306a36Sopenharmony_ci	int virtual_nci_fd;
30062306a36Sopenharmony_ci	bool open_state;
30162306a36Sopenharmony_ci	int dev_idex;
30262306a36Sopenharmony_ci	bool isNCI2;
30362306a36Sopenharmony_ci	int proto;
30462306a36Sopenharmony_ci	__u32 pid;
30562306a36Sopenharmony_ci	__u16 fid;
30662306a36Sopenharmony_ci	int sd;
30762306a36Sopenharmony_ci};
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ciFIXTURE_VARIANT(NCI) {
31062306a36Sopenharmony_ci	bool isNCI2;
31162306a36Sopenharmony_ci};
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(NCI, NCI1_0) {
31462306a36Sopenharmony_ci	.isNCI2 = false,
31562306a36Sopenharmony_ci};
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(NCI, NCI2_0) {
31862306a36Sopenharmony_ci	.isNCI2 = true,
31962306a36Sopenharmony_ci};
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic void *virtual_dev_open(void *data)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	char buf[258];
32462306a36Sopenharmony_ci	int dev_fd;
32562306a36Sopenharmony_ci	int len;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	dev_fd = *(int *)data;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
33062306a36Sopenharmony_ci	if (len <= 0)
33162306a36Sopenharmony_ci		goto error;
33262306a36Sopenharmony_ci	if (len != sizeof(nci_reset_cmd))
33362306a36Sopenharmony_ci		goto error;
33462306a36Sopenharmony_ci	if (memcmp(nci_reset_cmd, buf, len))
33562306a36Sopenharmony_ci		goto error;
33662306a36Sopenharmony_ci	write(dev_fd, nci_reset_rsp, sizeof(nci_reset_rsp));
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
33962306a36Sopenharmony_ci	if (len <= 0)
34062306a36Sopenharmony_ci		goto error;
34162306a36Sopenharmony_ci	if (len != sizeof(nci_init_cmd))
34262306a36Sopenharmony_ci		goto error;
34362306a36Sopenharmony_ci	if (memcmp(nci_init_cmd, buf, len))
34462306a36Sopenharmony_ci		goto error;
34562306a36Sopenharmony_ci	write(dev_fd, nci_init_rsp, sizeof(nci_init_rsp));
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
34862306a36Sopenharmony_ci	if (len <= 0)
34962306a36Sopenharmony_ci		goto error;
35062306a36Sopenharmony_ci	if (len != sizeof(nci_rf_disc_map_cmd))
35162306a36Sopenharmony_ci		goto error;
35262306a36Sopenharmony_ci	if (memcmp(nci_rf_disc_map_cmd, buf, len))
35362306a36Sopenharmony_ci		goto error;
35462306a36Sopenharmony_ci	write(dev_fd, nci_rf_disc_map_rsp, sizeof(nci_rf_disc_map_rsp));
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	return (void *)0;
35762306a36Sopenharmony_cierror:
35862306a36Sopenharmony_ci	return (void *)-1;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic void *virtual_dev_open_v2(void *data)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	char buf[258];
36462306a36Sopenharmony_ci	int dev_fd;
36562306a36Sopenharmony_ci	int len;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	dev_fd = *(int *)data;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
37062306a36Sopenharmony_ci	if (len <= 0)
37162306a36Sopenharmony_ci		goto error;
37262306a36Sopenharmony_ci	if (len != sizeof(nci_reset_cmd))
37362306a36Sopenharmony_ci		goto error;
37462306a36Sopenharmony_ci	if (memcmp(nci_reset_cmd, buf, len))
37562306a36Sopenharmony_ci		goto error;
37662306a36Sopenharmony_ci	write(dev_fd, nci_reset_rsp_v2, sizeof(nci_reset_rsp_v2));
37762306a36Sopenharmony_ci	write(dev_fd, nci_reset_ntf, sizeof(nci_reset_ntf));
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
38062306a36Sopenharmony_ci	if (len <= 0)
38162306a36Sopenharmony_ci		goto error;
38262306a36Sopenharmony_ci	if (len != sizeof(nci_init_cmd_v2))
38362306a36Sopenharmony_ci		goto error;
38462306a36Sopenharmony_ci	if (memcmp(nci_init_cmd_v2, buf, len))
38562306a36Sopenharmony_ci		goto error;
38662306a36Sopenharmony_ci	write(dev_fd, nci_init_rsp_v2, sizeof(nci_init_rsp_v2));
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
38962306a36Sopenharmony_ci	if (len <= 0)
39062306a36Sopenharmony_ci		goto error;
39162306a36Sopenharmony_ci	if (len != sizeof(nci_rf_disc_map_cmd))
39262306a36Sopenharmony_ci		goto error;
39362306a36Sopenharmony_ci	if (memcmp(nci_rf_disc_map_cmd, buf, len))
39462306a36Sopenharmony_ci		goto error;
39562306a36Sopenharmony_ci	write(dev_fd, nci_rf_disc_map_rsp, sizeof(nci_rf_disc_map_rsp));
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	return (void *)0;
39862306a36Sopenharmony_cierror:
39962306a36Sopenharmony_ci	return (void *)-1;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ciFIXTURE_SETUP(NCI)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct msgtemplate msg;
40562306a36Sopenharmony_ci	pthread_t thread_t;
40662306a36Sopenharmony_ci	__u32 event_group;
40762306a36Sopenharmony_ci	int status;
40862306a36Sopenharmony_ci	int rc;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	self->open_state = false;
41162306a36Sopenharmony_ci	self->proto = VIRTUAL_NFC_PROTOCOLS;
41262306a36Sopenharmony_ci	self->isNCI2 = variant->isNCI2;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	self->sd = create_nl_socket();
41562306a36Sopenharmony_ci	ASSERT_NE(self->sd, -1);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	self->pid = getpid();
41862306a36Sopenharmony_ci	self->fid = get_family_id(self->sd, self->pid, &event_group);
41962306a36Sopenharmony_ci	ASSERT_NE(self->fid, -1);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	self->virtual_nci_fd = open("/dev/virtual_nci", O_RDWR);
42262306a36Sopenharmony_ci	ASSERT_GT(self->virtual_nci_fd, -1);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	rc = setsockopt(self->sd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &event_group,
42562306a36Sopenharmony_ci			sizeof(event_group));
42662306a36Sopenharmony_ci	ASSERT_NE(rc, -1);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	rc = ioctl(self->virtual_nci_fd, IOCTL_GET_NCIDEV_IDX, &self->dev_idex);
42962306a36Sopenharmony_ci	ASSERT_EQ(rc, 0);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	rc = get_nci_devid(self->sd, self->fid, self->pid, self->dev_idex, &msg);
43262306a36Sopenharmony_ci	ASSERT_EQ(rc, 0);
43362306a36Sopenharmony_ci	EXPECT_EQ(get_dev_enable_state(&msg), 0);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (self->isNCI2)
43662306a36Sopenharmony_ci		rc = pthread_create(&thread_t, NULL, virtual_dev_open_v2,
43762306a36Sopenharmony_ci				    (void *)&self->virtual_nci_fd);
43862306a36Sopenharmony_ci	else
43962306a36Sopenharmony_ci		rc = pthread_create(&thread_t, NULL, virtual_dev_open,
44062306a36Sopenharmony_ci				    (void *)&self->virtual_nci_fd);
44162306a36Sopenharmony_ci	ASSERT_GT(rc, -1);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
44462306a36Sopenharmony_ci			       NFC_CMD_DEV_UP, self->dev_idex);
44562306a36Sopenharmony_ci	EXPECT_EQ(rc, 0);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	pthread_join(thread_t, (void **)&status);
44862306a36Sopenharmony_ci	ASSERT_EQ(status, 0);
44962306a36Sopenharmony_ci	self->open_state = true;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic void *virtual_deinit(void *data)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	char buf[258];
45562306a36Sopenharmony_ci	int dev_fd;
45662306a36Sopenharmony_ci	int len;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	dev_fd = *(int *)data;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
46162306a36Sopenharmony_ci	if (len <= 0)
46262306a36Sopenharmony_ci		goto error;
46362306a36Sopenharmony_ci	if (len != sizeof(nci_reset_cmd))
46462306a36Sopenharmony_ci		goto error;
46562306a36Sopenharmony_ci	if (memcmp(nci_reset_cmd, buf, len))
46662306a36Sopenharmony_ci		goto error;
46762306a36Sopenharmony_ci	write(dev_fd, nci_reset_rsp, sizeof(nci_reset_rsp));
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	return (void *)0;
47062306a36Sopenharmony_cierror:
47162306a36Sopenharmony_ci	return (void *)-1;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic void *virtual_deinit_v2(void *data)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	char buf[258];
47762306a36Sopenharmony_ci	int dev_fd;
47862306a36Sopenharmony_ci	int len;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	dev_fd = *(int *)data;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
48362306a36Sopenharmony_ci	if (len <= 0)
48462306a36Sopenharmony_ci		goto error;
48562306a36Sopenharmony_ci	if (len != sizeof(nci_reset_cmd))
48662306a36Sopenharmony_ci		goto error;
48762306a36Sopenharmony_ci	if (memcmp(nci_reset_cmd, buf, len))
48862306a36Sopenharmony_ci		goto error;
48962306a36Sopenharmony_ci	write(dev_fd, nci_reset_rsp_v2, sizeof(nci_reset_rsp_v2));
49062306a36Sopenharmony_ci	write(dev_fd, nci_reset_ntf, sizeof(nci_reset_ntf));
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	return (void *)0;
49362306a36Sopenharmony_cierror:
49462306a36Sopenharmony_ci	return (void *)-1;
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ciFIXTURE_TEARDOWN(NCI)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	pthread_t thread_t;
50062306a36Sopenharmony_ci	int status;
50162306a36Sopenharmony_ci	int rc;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	if (self->open_state) {
50462306a36Sopenharmony_ci		if (self->isNCI2)
50562306a36Sopenharmony_ci			rc = pthread_create(&thread_t, NULL,
50662306a36Sopenharmony_ci					    virtual_deinit_v2,
50762306a36Sopenharmony_ci					    (void *)&self->virtual_nci_fd);
50862306a36Sopenharmony_ci		else
50962306a36Sopenharmony_ci			rc = pthread_create(&thread_t, NULL, virtual_deinit,
51062306a36Sopenharmony_ci					    (void *)&self->virtual_nci_fd);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		ASSERT_GT(rc, -1);
51362306a36Sopenharmony_ci		rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
51462306a36Sopenharmony_ci				       NFC_CMD_DEV_DOWN, self->dev_idex);
51562306a36Sopenharmony_ci		EXPECT_EQ(rc, 0);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		pthread_join(thread_t, (void **)&status);
51862306a36Sopenharmony_ci		ASSERT_EQ(status, 0);
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	close(self->sd);
52262306a36Sopenharmony_ci	close(self->virtual_nci_fd);
52362306a36Sopenharmony_ci	self->open_state = false;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ciTEST_F(NCI, init)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	struct msgtemplate msg;
52962306a36Sopenharmony_ci	int rc;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	rc = get_nci_devid(self->sd, self->fid, self->pid, self->dev_idex,
53262306a36Sopenharmony_ci			   &msg);
53362306a36Sopenharmony_ci	ASSERT_EQ(rc, 0);
53462306a36Sopenharmony_ci	EXPECT_EQ(get_dev_enable_state(&msg), 1);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic void *virtual_poll_start(void *data)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	char buf[258];
54062306a36Sopenharmony_ci	int dev_fd;
54162306a36Sopenharmony_ci	int len;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	dev_fd = *(int *)data;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
54662306a36Sopenharmony_ci	if (len <= 0)
54762306a36Sopenharmony_ci		goto error;
54862306a36Sopenharmony_ci	if (len != sizeof(nci_rf_discovery_cmd))
54962306a36Sopenharmony_ci		goto error;
55062306a36Sopenharmony_ci	if (memcmp(nci_rf_discovery_cmd, buf, len))
55162306a36Sopenharmony_ci		goto error;
55262306a36Sopenharmony_ci	write(dev_fd, nci_rf_disc_rsp, sizeof(nci_rf_disc_rsp));
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	return (void *)0;
55562306a36Sopenharmony_cierror:
55662306a36Sopenharmony_ci	return (void *)-1;
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic void *virtual_poll_stop(void *data)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	char buf[258];
56262306a36Sopenharmony_ci	int dev_fd;
56362306a36Sopenharmony_ci	int len;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	dev_fd = *(int *)data;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	len = read(dev_fd, buf, 258);
56862306a36Sopenharmony_ci	if (len <= 0)
56962306a36Sopenharmony_ci		goto error;
57062306a36Sopenharmony_ci	if (len != sizeof(nci_rf_deact_cmd))
57162306a36Sopenharmony_ci		goto error;
57262306a36Sopenharmony_ci	if (memcmp(nci_rf_deact_cmd, buf, len))
57362306a36Sopenharmony_ci		goto error;
57462306a36Sopenharmony_ci	write(dev_fd, nci_rf_deact_rsp, sizeof(nci_rf_deact_rsp));
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	return (void *)0;
57762306a36Sopenharmony_cierror:
57862306a36Sopenharmony_ci	return (void *)-1;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ciint start_polling(int dev_idx, int proto, int virtual_fd, int sd, int fid, int pid)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	__u16 nla_start_poll_type[2] = {NFC_ATTR_DEVICE_INDEX,
58462306a36Sopenharmony_ci					 NFC_ATTR_PROTOCOLS};
58562306a36Sopenharmony_ci	void *nla_start_poll_data[2] = {&dev_idx, &proto};
58662306a36Sopenharmony_ci	int nla_start_poll_len[2] = {4, 4};
58762306a36Sopenharmony_ci	pthread_t thread_t;
58862306a36Sopenharmony_ci	int status;
58962306a36Sopenharmony_ci	int rc;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	rc = pthread_create(&thread_t, NULL, virtual_poll_start,
59262306a36Sopenharmony_ci			    (void *)&virtual_fd);
59362306a36Sopenharmony_ci	if (rc < 0)
59462306a36Sopenharmony_ci		return rc;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	rc = send_cmd_mt_nla(sd, fid, pid, NFC_CMD_START_POLL, 2, nla_start_poll_type,
59762306a36Sopenharmony_ci			     nla_start_poll_data, nla_start_poll_len, NLM_F_REQUEST);
59862306a36Sopenharmony_ci	if (rc != 0)
59962306a36Sopenharmony_ci		return rc;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	pthread_join(thread_t, (void **)&status);
60262306a36Sopenharmony_ci	return status;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ciint stop_polling(int dev_idx, int virtual_fd, int sd, int fid, int pid)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	pthread_t thread_t;
60862306a36Sopenharmony_ci	int status;
60962306a36Sopenharmony_ci	int rc;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	rc = pthread_create(&thread_t, NULL, virtual_poll_stop,
61262306a36Sopenharmony_ci			    (void *)&virtual_fd);
61362306a36Sopenharmony_ci	if (rc < 0)
61462306a36Sopenharmony_ci		return rc;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	rc = send_cmd_with_idx(sd, fid, pid,
61762306a36Sopenharmony_ci			       NFC_CMD_STOP_POLL, dev_idx);
61862306a36Sopenharmony_ci	if (rc != 0)
61962306a36Sopenharmony_ci		return rc;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	pthread_join(thread_t, (void **)&status);
62262306a36Sopenharmony_ci	return status;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ciTEST_F(NCI, start_poll)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	int status;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	status = start_polling(self->dev_idex, self->proto, self->virtual_nci_fd,
63062306a36Sopenharmony_ci			       self->sd, self->fid, self->pid);
63162306a36Sopenharmony_ci	EXPECT_EQ(status, 0);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	status = stop_polling(self->dev_idex, self->virtual_nci_fd, self->sd,
63462306a36Sopenharmony_ci			      self->fid, self->pid);
63562306a36Sopenharmony_ci	EXPECT_EQ(status, 0);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ciint get_taginfo(int dev_idx, int sd, int fid, int pid)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct {
64162306a36Sopenharmony_ci		struct nlmsghdr n;
64262306a36Sopenharmony_ci		struct genlmsghdr g;
64362306a36Sopenharmony_ci		char buf[512];
64462306a36Sopenharmony_ci	} ans;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	struct nlattr *na;
64762306a36Sopenharmony_ci	__u32 protocol;
64862306a36Sopenharmony_ci	int targetidx;
64962306a36Sopenharmony_ci	__u8 sel_res;
65062306a36Sopenharmony_ci	int resp_len;
65162306a36Sopenharmony_ci	int len;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	__u16 tagid_type;
65462306a36Sopenharmony_ci	void *tagid_type_data;
65562306a36Sopenharmony_ci	int tagid_len;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	tagid_type = NFC_ATTR_DEVICE_INDEX;
65862306a36Sopenharmony_ci	tagid_type_data = &dev_idx;
65962306a36Sopenharmony_ci	tagid_len = 4;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	send_cmd_mt_nla(sd, fid, pid, NFC_CMD_GET_TARGET, 1, &tagid_type,
66262306a36Sopenharmony_ci			&tagid_type_data, &tagid_len, NLM_F_REQUEST | NLM_F_DUMP);
66362306a36Sopenharmony_ci	resp_len = recv(sd, &ans, sizeof(ans), 0);
66462306a36Sopenharmony_ci	if (ans.n.nlmsg_type == NLMSG_ERROR || resp_len < 0 ||
66562306a36Sopenharmony_ci	    !NLMSG_OK(&ans.n, resp_len))
66662306a36Sopenharmony_ci		return -1;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	resp_len = GENLMSG_PAYLOAD(&ans.n);
66962306a36Sopenharmony_ci	na = (struct nlattr *)GENLMSG_DATA(&ans);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	len = 0;
67262306a36Sopenharmony_ci	targetidx = -1;
67362306a36Sopenharmony_ci	protocol = -1;
67462306a36Sopenharmony_ci	sel_res = -1;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	while (len < resp_len) {
67762306a36Sopenharmony_ci		len += NLA_ALIGN(na->nla_len);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		if (na->nla_type == NFC_ATTR_TARGET_INDEX)
68062306a36Sopenharmony_ci			targetidx = *(int *)((char *)na + NLA_HDRLEN);
68162306a36Sopenharmony_ci		else if (na->nla_type == NFC_ATTR_TARGET_SEL_RES)
68262306a36Sopenharmony_ci			sel_res = *(__u8 *)((char *)na + NLA_HDRLEN);
68362306a36Sopenharmony_ci		else if (na->nla_type == NFC_ATTR_PROTOCOLS)
68462306a36Sopenharmony_ci			protocol = *(__u32 *)((char *)na + NLA_HDRLEN);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		na = (struct nlattr *)(GENLMSG_DATA(&ans) + len);
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	if (targetidx == -1 || sel_res != 0x20 || protocol != NFC_PROTO_ISO14443_MASK)
69062306a36Sopenharmony_ci		return -1;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	return targetidx;
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ciint connect_socket(int dev_idx, int target_idx)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	struct sockaddr_nfc addr;
69862306a36Sopenharmony_ci	int sock;
69962306a36Sopenharmony_ci	int err = 0;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	sock = socket(AF_NFC, SOCK_SEQPACKET, NFC_SOCKPROTO_RAW);
70262306a36Sopenharmony_ci	if (sock == -1)
70362306a36Sopenharmony_ci		return -1;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	addr.sa_family = AF_NFC;
70662306a36Sopenharmony_ci	addr.dev_idx = dev_idx;
70762306a36Sopenharmony_ci	addr.target_idx = target_idx;
70862306a36Sopenharmony_ci	addr.nfc_protocol = NFC_PROTO_ISO14443;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	err = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
71162306a36Sopenharmony_ci	if (err) {
71262306a36Sopenharmony_ci		close(sock);
71362306a36Sopenharmony_ci		return -1;
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	return sock;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ciint connect_tag(int dev_idx, int virtual_fd, int sd, int fid, int pid)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	struct genlmsghdr *genlhdr;
72262306a36Sopenharmony_ci	struct nlattr *na;
72362306a36Sopenharmony_ci	char evt_data[255];
72462306a36Sopenharmony_ci	int target_idx;
72562306a36Sopenharmony_ci	int resp_len;
72662306a36Sopenharmony_ci	int evt_dev;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	write(virtual_fd, nci_rf_activate_ntf, sizeof(nci_rf_activate_ntf));
72962306a36Sopenharmony_ci	resp_len = recv(sd, evt_data, sizeof(evt_data), 0);
73062306a36Sopenharmony_ci	if (resp_len < 0)
73162306a36Sopenharmony_ci		return -1;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	genlhdr = (struct genlmsghdr *)((struct nlmsghdr *)evt_data + 1);
73462306a36Sopenharmony_ci	na = (struct nlattr *)(genlhdr + 1);
73562306a36Sopenharmony_ci	evt_dev = *(int *)((char *)na + NLA_HDRLEN);
73662306a36Sopenharmony_ci	if (dev_idx != evt_dev)
73762306a36Sopenharmony_ci		return -1;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	target_idx = get_taginfo(dev_idx, sd, fid, pid);
74062306a36Sopenharmony_ci	if (target_idx == -1)
74162306a36Sopenharmony_ci		return -1;
74262306a36Sopenharmony_ci	return connect_socket(dev_idx, target_idx);
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ciint read_write_nci_cmd(int nfc_sock, int virtual_fd, const __u8 *cmd, __u32 cmd_len,
74662306a36Sopenharmony_ci		       const __u8 *rsp, __u32 rsp_len)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	char buf[256];
74962306a36Sopenharmony_ci	int len;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	send(nfc_sock, &cmd[3], cmd_len - 3, 0);
75262306a36Sopenharmony_ci	len = read(virtual_fd, buf, cmd_len);
75362306a36Sopenharmony_ci	if (len < 0 || memcmp(buf, cmd, cmd_len))
75462306a36Sopenharmony_ci		return -1;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	write(virtual_fd, rsp, rsp_len);
75762306a36Sopenharmony_ci	len = recv(nfc_sock, buf, rsp_len - 2, 0);
75862306a36Sopenharmony_ci	if (len < 0 || memcmp(&buf[1], &rsp[3], rsp_len - 3))
75962306a36Sopenharmony_ci		return -1;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	return 0;
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ciint read_tag(int nfc_sock, int virtual_fd)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_select_cmd,
76762306a36Sopenharmony_ci			       sizeof(nci_t4t_select_cmd), nci_t4t_rsp_ok,
76862306a36Sopenharmony_ci			       sizeof(nci_t4t_rsp_ok)))
76962306a36Sopenharmony_ci		return -1;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_select_cmd2,
77262306a36Sopenharmony_ci			       sizeof(nci_t4t_select_cmd2), nci_t4t_rsp_ok,
77362306a36Sopenharmony_ci			       sizeof(nci_t4t_rsp_ok)))
77462306a36Sopenharmony_ci		return -1;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_read_cmd,
77762306a36Sopenharmony_ci			       sizeof(nci_t4t_read_cmd), nci_t4t_read_rsp,
77862306a36Sopenharmony_ci			       sizeof(nci_t4t_read_rsp)))
77962306a36Sopenharmony_ci		return -1;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_select_cmd3,
78262306a36Sopenharmony_ci			       sizeof(nci_t4t_select_cmd3), nci_t4t_rsp_ok,
78362306a36Sopenharmony_ci			       sizeof(nci_t4t_rsp_ok)))
78462306a36Sopenharmony_ci		return -1;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_read_cmd2,
78762306a36Sopenharmony_ci			       sizeof(nci_t4t_read_cmd2), nci_t4t_read_rsp2,
78862306a36Sopenharmony_ci			       sizeof(nci_t4t_read_rsp2)))
78962306a36Sopenharmony_ci		return -1;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	return read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_read_cmd3,
79262306a36Sopenharmony_ci				  sizeof(nci_t4t_read_cmd3), nci_t4t_read_rsp3,
79362306a36Sopenharmony_ci				  sizeof(nci_t4t_read_rsp3));
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic void *virtual_deactivate_proc(void *data)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	int virtual_fd;
79962306a36Sopenharmony_ci	char buf[256];
80062306a36Sopenharmony_ci	int deactcmd_len;
80162306a36Sopenharmony_ci	int len;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	virtual_fd = *(int *)data;
80462306a36Sopenharmony_ci	deactcmd_len = sizeof(nci_rf_deact_cmd);
80562306a36Sopenharmony_ci	len = read(virtual_fd, buf, deactcmd_len);
80662306a36Sopenharmony_ci	if (len != deactcmd_len || memcmp(buf, nci_rf_deact_cmd, deactcmd_len))
80762306a36Sopenharmony_ci		return (void *)-1;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	write(virtual_fd, nci_rf_deact_rsp, sizeof(nci_rf_deact_rsp));
81062306a36Sopenharmony_ci	write(virtual_fd, nci_rf_deact_ntf, sizeof(nci_rf_deact_ntf));
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	return (void *)0;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ciint disconnect_tag(int nfc_sock, int virtual_fd)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	pthread_t thread_t;
81862306a36Sopenharmony_ci	char buf[256];
81962306a36Sopenharmony_ci	int status;
82062306a36Sopenharmony_ci	int len;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	send(nfc_sock, &nci_t4t_select_cmd3[3], sizeof(nci_t4t_select_cmd3) - 3, 0);
82362306a36Sopenharmony_ci	len = read(virtual_fd, buf, sizeof(nci_t4t_select_cmd3));
82462306a36Sopenharmony_ci	if (len < 0 || memcmp(buf, nci_t4t_select_cmd3, sizeof(nci_t4t_select_cmd3)))
82562306a36Sopenharmony_ci		return -1;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	len = recv(nfc_sock, buf, sizeof(nci_t4t_rsp_ok), 0);
82862306a36Sopenharmony_ci	if (len != -1)
82962306a36Sopenharmony_ci		return -1;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	status = pthread_create(&thread_t, NULL, virtual_deactivate_proc,
83262306a36Sopenharmony_ci				(void *)&virtual_fd);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	close(nfc_sock);
83562306a36Sopenharmony_ci	pthread_join(thread_t, (void **)&status);
83662306a36Sopenharmony_ci	return status;
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ciTEST_F(NCI, t4t_tag_read)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	int nfc_sock;
84262306a36Sopenharmony_ci	int status;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	status = start_polling(self->dev_idex, self->proto, self->virtual_nci_fd,
84562306a36Sopenharmony_ci			       self->sd, self->fid, self->pid);
84662306a36Sopenharmony_ci	EXPECT_EQ(status, 0);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	nfc_sock = connect_tag(self->dev_idex, self->virtual_nci_fd, self->sd,
84962306a36Sopenharmony_ci			       self->fid, self->pid);
85062306a36Sopenharmony_ci	ASSERT_GT(nfc_sock, -1);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	status = read_tag(nfc_sock, self->virtual_nci_fd);
85362306a36Sopenharmony_ci	ASSERT_EQ(status, 0);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	status = disconnect_tag(nfc_sock, self->virtual_nci_fd);
85662306a36Sopenharmony_ci	EXPECT_EQ(status, 0);
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ciTEST_F(NCI, deinit)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	struct msgtemplate msg;
86262306a36Sopenharmony_ci	pthread_t thread_t;
86362306a36Sopenharmony_ci	int status;
86462306a36Sopenharmony_ci	int rc;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	rc = get_nci_devid(self->sd, self->fid, self->pid, self->dev_idex,
86762306a36Sopenharmony_ci			   &msg);
86862306a36Sopenharmony_ci	ASSERT_EQ(rc, 0);
86962306a36Sopenharmony_ci	EXPECT_EQ(get_dev_enable_state(&msg), 1);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	if (self->isNCI2)
87262306a36Sopenharmony_ci		rc = pthread_create(&thread_t, NULL, virtual_deinit_v2,
87362306a36Sopenharmony_ci				    (void *)&self->virtual_nci_fd);
87462306a36Sopenharmony_ci	else
87562306a36Sopenharmony_ci		rc = pthread_create(&thread_t, NULL, virtual_deinit,
87662306a36Sopenharmony_ci				    (void *)&self->virtual_nci_fd);
87762306a36Sopenharmony_ci	ASSERT_GT(rc, -1);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
88062306a36Sopenharmony_ci			       NFC_CMD_DEV_DOWN, self->dev_idex);
88162306a36Sopenharmony_ci	EXPECT_EQ(rc, 0);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	pthread_join(thread_t, (void **)&status);
88462306a36Sopenharmony_ci	self->open_state = 0;
88562306a36Sopenharmony_ci	ASSERT_EQ(status, 0);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	rc = get_nci_devid(self->sd, self->fid, self->pid, self->dev_idex,
88862306a36Sopenharmony_ci			   &msg);
88962306a36Sopenharmony_ci	ASSERT_EQ(rc, 0);
89062306a36Sopenharmony_ci	EXPECT_EQ(get_dev_enable_state(&msg), 0);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	/* Test that operations that normally send packets to the driver
89362306a36Sopenharmony_ci	 * don't cause issues when the device is already closed.
89462306a36Sopenharmony_ci	 * Note: the send of NFC_CMD_DEV_UP itself still succeeds it's just
89562306a36Sopenharmony_ci	 * that the device won't actually be up.
89662306a36Sopenharmony_ci	 */
89762306a36Sopenharmony_ci	close(self->virtual_nci_fd);
89862306a36Sopenharmony_ci	self->virtual_nci_fd = -1;
89962306a36Sopenharmony_ci	rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
90062306a36Sopenharmony_ci			       NFC_CMD_DEV_UP, self->dev_idex);
90162306a36Sopenharmony_ci	EXPECT_EQ(rc, 0);
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ciTEST_HARNESS_MAIN
905