Files
linux/tools/testing/selftests/nci/nci_dev.c
Bongsu Jeon 61612511e5 selftests: nci: Add the NCI testcase reading T4T Tag
Add the NCI testcase reading T4T Tag that has NFC TEST in plain text.
the virtual device application acts as T4T Tag in this testcase.

Signed-off-by: Bongsu Jeon <bongsu.jeon@samsung.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-08-18 10:17:57 +01:00

894 lines
21 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 Samsung Electrnoics
* Bongsu Jeon <bongsu.jeon@samsung.com>
*
* Test code for nci
*/
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <pthread.h>
#include <linux/genetlink.h>
#include <sys/socket.h>
#include <linux/nfc.h>
#include "../kselftest_harness.h"
#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
#define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN))
#define NLA_PAYLOAD(len) ((len) - NLA_HDRLEN)
#define MAX_MSG_SIZE 1024
#define IOCTL_GET_NCIDEV_IDX 0
#define VIRTUAL_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
NFC_PROTO_MIFARE_MASK | \
NFC_PROTO_FELICA_MASK | \
NFC_PROTO_ISO14443_MASK | \
NFC_PROTO_ISO14443_B_MASK | \
NFC_PROTO_ISO15693_MASK)
const __u8 nci_reset_cmd[] = {0x20, 0x00, 0x01, 0x01};
const __u8 nci_init_cmd[] = {0x20, 0x01, 0x00};
const __u8 nci_rf_discovery_cmd[] = {0x21, 0x03, 0x09, 0x04, 0x00, 0x01,
0x01, 0x01, 0x02, 0x01, 0x06, 0x01};
const __u8 nci_init_cmd_v2[] = {0x20, 0x01, 0x02, 0x00, 0x00};
const __u8 nci_rf_disc_map_cmd[] = {0x21, 0x00, 0x07, 0x02, 0x04, 0x03,
0x02, 0x05, 0x03, 0x03};
const __u8 nci_rf_deact_cmd[] = {0x21, 0x06, 0x01, 0x00};
const __u8 nci_reset_rsp[] = {0x40, 0x00, 0x03, 0x00, 0x10, 0x01};
const __u8 nci_reset_rsp_v2[] = {0x40, 0x00, 0x01, 0x00};
const __u8 nci_reset_ntf[] = {0x60, 0x00, 0x09, 0x02, 0x01, 0x20, 0x0e,
0x04, 0x61, 0x00, 0x04, 0x02};
const __u8 nci_init_rsp[] = {0x40, 0x01, 0x14, 0x00, 0x02, 0x0e, 0x02,
0x00, 0x03, 0x01, 0x02, 0x03, 0x02, 0xc8,
0x00, 0xff, 0x10, 0x00, 0x0e, 0x12, 0x00,
0x00, 0x04};
const __u8 nci_init_rsp_v2[] = {0x40, 0x01, 0x1c, 0x00, 0x1a, 0x7e, 0x06,
0x00, 0x02, 0x92, 0x04, 0xff, 0xff, 0x01,
0x00, 0x40, 0x06, 0x00, 0x00, 0x01, 0x01,
0x00, 0x02, 0x00, 0x03, 0x01, 0x01, 0x06,
0x00, 0x80, 0x00};
const __u8 nci_rf_disc_map_rsp[] = {0x41, 0x00, 0x01, 0x00};
const __u8 nci_rf_disc_rsp[] = {0x41, 0x03, 0x01, 0x00};
const __u8 nci_rf_deact_rsp[] = {0x41, 0x06, 0x01, 0x00};
const __u8 nci_rf_deact_ntf[] = {0x61, 0x06, 0x02, 0x00, 0x00};
const __u8 nci_rf_activate_ntf[] = {0x61, 0x05, 0x1D, 0x01, 0x02, 0x04, 0x00,
0xFF, 0xFF, 0x0C, 0x44, 0x03, 0x07, 0x04,
0x62, 0x26, 0x11, 0x80, 0x1D, 0x80, 0x01,
0x20, 0x00, 0x00, 0x00, 0x06, 0x05, 0x75,
0x77, 0x81, 0x02, 0x80};
const __u8 nci_t4t_select_cmd[] = {0x00, 0x00, 0x0C, 0x00, 0xA4, 0x04, 0x00,
0x07, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01};
const __u8 nci_t4t_select_cmd2[] = {0x00, 0x00, 0x07, 0x00, 0xA4, 0x00, 0x0C, 0x02,
0xE1, 0x03};
const __u8 nci_t4t_select_cmd3[] = {0x00, 0x00, 0x07, 0x00, 0xA4, 0x00, 0x0C, 0x02,
0xE1, 0x04};
const __u8 nci_t4t_read_cmd[] = {0x00, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x00, 0x0F};
const __u8 nci_t4t_read_rsp[] = {0x00, 0x00, 0x11, 0x00, 0x0F, 0x20, 0x00, 0x3B,
0x00, 0x34, 0x04, 0x06, 0xE1, 0x04, 0x08, 0x00,
0x00, 0x00, 0x90, 0x00};
const __u8 nci_t4t_read_cmd2[] = {0x00, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x00, 0x02};
const __u8 nci_t4t_read_rsp2[] = {0x00, 0x00, 0x04, 0x00, 0x0F, 0x90, 0x00};
const __u8 nci_t4t_read_cmd3[] = {0x00, 0x00, 0x05, 0x00, 0xB0, 0x00, 0x02, 0x0F};
const __u8 nci_t4t_read_rsp3[] = {0x00, 0x00, 0x11, 0xD1, 0x01, 0x0B, 0x54, 0x02,
0x65, 0x6E, 0x4E, 0x46, 0x43, 0x20, 0x54, 0x45,
0x53, 0x54, 0x90, 0x00};
const __u8 nci_t4t_rsp_ok[] = {0x00, 0x00, 0x02, 0x90, 0x00};
struct msgtemplate {
struct nlmsghdr n;
struct genlmsghdr g;
char buf[MAX_MSG_SIZE];
};
static int create_nl_socket(void)
{
int fd;
struct sockaddr_nl local;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
if (fd < 0)
return -1;
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0)
goto error;
return fd;
error:
close(fd);
return -1;
}
static int send_cmd_mt_nla(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
__u8 genl_cmd, int nla_num, __u16 nla_type[],
void *nla_data[], int nla_len[], __u16 flags)
{
struct sockaddr_nl nladdr;
struct msgtemplate msg;
struct nlattr *na;
int cnt, prv_len;
int r, buflen;
char *buf;
msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
msg.n.nlmsg_type = nlmsg_type;
msg.n.nlmsg_flags = flags;
msg.n.nlmsg_seq = 0;
msg.n.nlmsg_pid = nlmsg_pid;
msg.g.cmd = genl_cmd;
msg.g.version = 0x1;
prv_len = 0;
for (cnt = 0; cnt < nla_num; cnt++) {
na = (struct nlattr *)(GENLMSG_DATA(&msg) + prv_len);
na->nla_type = nla_type[cnt];
na->nla_len = nla_len[cnt] + NLA_HDRLEN;
if (nla_len[cnt] > 0)
memcpy(NLA_DATA(na), nla_data[cnt], nla_len[cnt]);
prv_len = NLA_ALIGN(nla_len[cnt]) + NLA_HDRLEN;
msg.n.nlmsg_len += prv_len;
}
buf = (char *)&msg;
buflen = msg.n.nlmsg_len;
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *)&nladdr,
sizeof(nladdr))) < buflen) {
if (r > 0) {
buf += r;
buflen -= r;
} else if (errno != EAGAIN) {
return -1;
}
}
return 0;
}
static int send_get_nfc_family(int sd, __u32 pid)
{
__u16 nla_get_family_type = CTRL_ATTR_FAMILY_NAME;
void *nla_get_family_data;
int nla_get_family_len;
char family_name[100];
nla_get_family_len = strlen(NFC_GENL_NAME) + 1;
strcpy(family_name, NFC_GENL_NAME);
nla_get_family_data = family_name;
return send_cmd_mt_nla(sd, GENL_ID_CTRL, pid, CTRL_CMD_GETFAMILY,
1, &nla_get_family_type, &nla_get_family_data,
&nla_get_family_len, NLM_F_REQUEST);
}
static int get_family_id(int sd, __u32 pid, __u32 *event_group)
{
struct {
struct nlmsghdr n;
struct genlmsghdr g;
char buf[512];
} ans;
struct nlattr *na;
int resp_len;
__u16 id;
int len;
int rc;
rc = send_get_nfc_family(sd, pid);
if (rc < 0)
return 0;
resp_len = recv(sd, &ans, sizeof(ans), 0);
if (ans.n.nlmsg_type == NLMSG_ERROR || resp_len < 0 ||
!NLMSG_OK(&ans.n, resp_len))
return 0;
len = 0;
resp_len = GENLMSG_PAYLOAD(&ans.n);
na = (struct nlattr *)GENLMSG_DATA(&ans);
while (len < resp_len) {
len += NLA_ALIGN(na->nla_len);
if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
id = *(__u16 *)NLA_DATA(na);
} else if (na->nla_type == CTRL_ATTR_MCAST_GROUPS) {
struct nlattr *nested_na;
struct nlattr *group_na;
int group_attr_len;
int group_attr;
nested_na = (struct nlattr *)((char *)na + NLA_HDRLEN);
group_na = (struct nlattr *)((char *)nested_na + NLA_HDRLEN);
group_attr_len = 0;
for (group_attr = CTRL_ATTR_MCAST_GRP_UNSPEC;
group_attr < CTRL_ATTR_MCAST_GRP_MAX; group_attr++) {
if (group_na->nla_type == CTRL_ATTR_MCAST_GRP_ID) {
*event_group = *(__u32 *)((char *)group_na +
NLA_HDRLEN);
break;
}
group_attr_len += NLA_ALIGN(group_na->nla_len) +
NLA_HDRLEN;
if (group_attr_len >= nested_na->nla_len)
break;
group_na = (struct nlattr *)((char *)group_na +
NLA_ALIGN(group_na->nla_len));
}
}
na = (struct nlattr *)(GENLMSG_DATA(&ans) + len);
}
return id;
}
static int send_cmd_with_idx(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
__u8 genl_cmd, int dev_id)
{
__u16 nla_type = NFC_ATTR_DEVICE_INDEX;
void *nla_data = &dev_id;
int nla_len = 4;
return send_cmd_mt_nla(sd, nlmsg_type, nlmsg_pid, genl_cmd, 1,
&nla_type, &nla_data, &nla_len, NLM_F_REQUEST);
}
static int get_nci_devid(int sd, __u16 fid, __u32 pid, int dev_id, struct msgtemplate *msg)
{
int rc, resp_len;
rc = send_cmd_with_idx(sd, fid, pid, NFC_CMD_GET_DEVICE, dev_id);
if (rc < 0) {
rc = -1;
goto error;
}
resp_len = recv(sd, msg, sizeof(*msg), 0);
if (resp_len < 0) {
rc = -2;
goto error;
}
if (msg->n.nlmsg_type == NLMSG_ERROR ||
!NLMSG_OK(&msg->n, resp_len)) {
rc = -3;
goto error;
}
return 0;
error:
return rc;
}
static __u8 get_dev_enable_state(struct msgtemplate *msg)
{
struct nlattr *na;
int resp_len;
int len;
resp_len = GENLMSG_PAYLOAD(&msg->n);
na = (struct nlattr *)GENLMSG_DATA(msg);
len = 0;
while (len < resp_len) {
len += NLA_ALIGN(na->nla_len);
if (na->nla_type == NFC_ATTR_DEVICE_POWERED)
return *(char *)NLA_DATA(na);
na = (struct nlattr *)(GENLMSG_DATA(msg) + len);
}
return resp_len;
}
FIXTURE(NCI) {
int virtual_nci_fd;
bool open_state;
int dev_idex;
bool isNCI2;
int proto;
__u32 pid;
__u16 fid;
int sd;
};
FIXTURE_VARIANT(NCI) {
bool isNCI2;
};
FIXTURE_VARIANT_ADD(NCI, NCI1_0) {
.isNCI2 = false,
};
FIXTURE_VARIANT_ADD(NCI, NCI2_0) {
.isNCI2 = true,
};
static void *virtual_dev_open(void *data)
{
char buf[258];
int dev_fd;
int len;
dev_fd = *(int *)data;
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_reset_cmd))
goto error;
if (memcmp(nci_reset_cmd, buf, len))
goto error;
write(dev_fd, nci_reset_rsp, sizeof(nci_reset_rsp));
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_init_cmd))
goto error;
if (memcmp(nci_init_cmd, buf, len))
goto error;
write(dev_fd, nci_init_rsp, sizeof(nci_init_rsp));
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_rf_disc_map_cmd))
goto error;
if (memcmp(nci_rf_disc_map_cmd, buf, len))
goto error;
write(dev_fd, nci_rf_disc_map_rsp, sizeof(nci_rf_disc_map_rsp));
return (void *)0;
error:
return (void *)-1;
}
static void *virtual_dev_open_v2(void *data)
{
char buf[258];
int dev_fd;
int len;
dev_fd = *(int *)data;
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_reset_cmd))
goto error;
if (memcmp(nci_reset_cmd, buf, len))
goto error;
write(dev_fd, nci_reset_rsp_v2, sizeof(nci_reset_rsp_v2));
write(dev_fd, nci_reset_ntf, sizeof(nci_reset_ntf));
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_init_cmd_v2))
goto error;
if (memcmp(nci_init_cmd_v2, buf, len))
goto error;
write(dev_fd, nci_init_rsp_v2, sizeof(nci_init_rsp_v2));
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_rf_disc_map_cmd))
goto error;
if (memcmp(nci_rf_disc_map_cmd, buf, len))
goto error;
write(dev_fd, nci_rf_disc_map_rsp, sizeof(nci_rf_disc_map_rsp));
return (void *)0;
error:
return (void *)-1;
}
FIXTURE_SETUP(NCI)
{
struct msgtemplate msg;
pthread_t thread_t;
__u32 event_group;
int status;
int rc;
self->open_state = false;
self->proto = VIRTUAL_NFC_PROTOCOLS;
self->isNCI2 = variant->isNCI2;
self->sd = create_nl_socket();
ASSERT_NE(self->sd, -1);
self->pid = getpid();
self->fid = get_family_id(self->sd, self->pid, &event_group);
ASSERT_NE(self->fid, -1);
self->virtual_nci_fd = open("/dev/virtual_nci", O_RDWR);
ASSERT_GT(self->virtual_nci_fd, -1);
rc = setsockopt(self->sd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &event_group,
sizeof(event_group));
ASSERT_NE(rc, -1);
rc = ioctl(self->virtual_nci_fd, IOCTL_GET_NCIDEV_IDX, &self->dev_idex);
ASSERT_EQ(rc, 0);
rc = get_nci_devid(self->sd, self->fid, self->pid, self->dev_idex, &msg);
ASSERT_EQ(rc, 0);
EXPECT_EQ(get_dev_enable_state(&msg), 0);
if (self->isNCI2)
rc = pthread_create(&thread_t, NULL, virtual_dev_open_v2,
(void *)&self->virtual_nci_fd);
else
rc = pthread_create(&thread_t, NULL, virtual_dev_open,
(void *)&self->virtual_nci_fd);
ASSERT_GT(rc, -1);
rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
NFC_CMD_DEV_UP, self->dev_idex);
EXPECT_EQ(rc, 0);
pthread_join(thread_t, (void **)&status);
ASSERT_EQ(status, 0);
self->open_state = true;
}
static void *virtual_deinit(void *data)
{
char buf[258];
int dev_fd;
int len;
dev_fd = *(int *)data;
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_reset_cmd))
goto error;
if (memcmp(nci_reset_cmd, buf, len))
goto error;
write(dev_fd, nci_reset_rsp, sizeof(nci_reset_rsp));
return (void *)0;
error:
return (void *)-1;
}
static void *virtual_deinit_v2(void *data)
{
char buf[258];
int dev_fd;
int len;
dev_fd = *(int *)data;
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_reset_cmd))
goto error;
if (memcmp(nci_reset_cmd, buf, len))
goto error;
write(dev_fd, nci_reset_rsp_v2, sizeof(nci_reset_rsp_v2));
write(dev_fd, nci_reset_ntf, sizeof(nci_reset_ntf));
return (void *)0;
error:
return (void *)-1;
}
FIXTURE_TEARDOWN(NCI)
{
pthread_t thread_t;
int status;
int rc;
if (self->open_state) {
if (self->isNCI2)
rc = pthread_create(&thread_t, NULL,
virtual_deinit_v2,
(void *)&self->virtual_nci_fd);
else
rc = pthread_create(&thread_t, NULL, virtual_deinit,
(void *)&self->virtual_nci_fd);
ASSERT_GT(rc, -1);
rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
NFC_CMD_DEV_DOWN, self->dev_idex);
EXPECT_EQ(rc, 0);
pthread_join(thread_t, (void **)&status);
ASSERT_EQ(status, 0);
}
close(self->sd);
close(self->virtual_nci_fd);
self->open_state = false;
}
TEST_F(NCI, init)
{
struct msgtemplate msg;
int rc;
rc = get_nci_devid(self->sd, self->fid, self->pid, self->dev_idex,
&msg);
ASSERT_EQ(rc, 0);
EXPECT_EQ(get_dev_enable_state(&msg), 1);
}
static void *virtual_poll_start(void *data)
{
char buf[258];
int dev_fd;
int len;
dev_fd = *(int *)data;
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_rf_discovery_cmd))
goto error;
if (memcmp(nci_rf_discovery_cmd, buf, len))
goto error;
write(dev_fd, nci_rf_disc_rsp, sizeof(nci_rf_disc_rsp));
return (void *)0;
error:
return (void *)-1;
}
static void *virtual_poll_stop(void *data)
{
char buf[258];
int dev_fd;
int len;
dev_fd = *(int *)data;
len = read(dev_fd, buf, 258);
if (len <= 0)
goto error;
if (len != sizeof(nci_rf_deact_cmd))
goto error;
if (memcmp(nci_rf_deact_cmd, buf, len))
goto error;
write(dev_fd, nci_rf_deact_rsp, sizeof(nci_rf_deact_rsp));
return (void *)0;
error:
return (void *)-1;
}
int start_polling(int dev_idx, int proto, int virtual_fd, int sd, int fid, int pid)
{
__u16 nla_start_poll_type[2] = {NFC_ATTR_DEVICE_INDEX,
NFC_ATTR_PROTOCOLS};
void *nla_start_poll_data[2] = {&dev_idx, &proto};
int nla_start_poll_len[2] = {4, 4};
pthread_t thread_t;
int status;
int rc;
rc = pthread_create(&thread_t, NULL, virtual_poll_start,
(void *)&virtual_fd);
if (rc < 0)
return rc;
rc = send_cmd_mt_nla(sd, fid, pid, NFC_CMD_START_POLL, 2, nla_start_poll_type,
nla_start_poll_data, nla_start_poll_len, NLM_F_REQUEST);
if (rc != 0)
return rc;
pthread_join(thread_t, (void **)&status);
return status;
}
int stop_polling(int dev_idx, int virtual_fd, int sd, int fid, int pid)
{
pthread_t thread_t;
int status;
int rc;
rc = pthread_create(&thread_t, NULL, virtual_poll_stop,
(void *)&virtual_fd);
if (rc < 0)
return rc;
rc = send_cmd_with_idx(sd, fid, pid,
NFC_CMD_STOP_POLL, dev_idx);
if (rc != 0)
return rc;
pthread_join(thread_t, (void **)&status);
return status;
}
TEST_F(NCI, start_poll)
{
int status;
status = start_polling(self->dev_idex, self->proto, self->virtual_nci_fd,
self->sd, self->fid, self->pid);
EXPECT_EQ(status, 0);
status = stop_polling(self->dev_idex, self->virtual_nci_fd, self->sd,
self->fid, self->pid);
EXPECT_EQ(status, 0);
}
int get_taginfo(int dev_idx, int sd, int fid, int pid)
{
struct {
struct nlmsghdr n;
struct genlmsghdr g;
char buf[512];
} ans;
struct nlattr *na;
__u32 protocol;
int targetidx;
__u8 sel_res;
int resp_len;
int len;
__u16 tagid_type;
void *tagid_type_data;
int tagid_len;
tagid_type = NFC_ATTR_DEVICE_INDEX;
tagid_type_data = &dev_idx;
tagid_len = 4;
send_cmd_mt_nla(sd, fid, pid, NFC_CMD_GET_TARGET, 1, &tagid_type,
&tagid_type_data, &tagid_len, NLM_F_REQUEST | NLM_F_DUMP);
resp_len = recv(sd, &ans, sizeof(ans), 0);
if (ans.n.nlmsg_type == NLMSG_ERROR || resp_len < 0 ||
!NLMSG_OK(&ans.n, resp_len))
return -1;
resp_len = GENLMSG_PAYLOAD(&ans.n);
na = (struct nlattr *)GENLMSG_DATA(&ans);
len = 0;
targetidx = -1;
protocol = -1;
sel_res = -1;
while (len < resp_len) {
len += NLA_ALIGN(na->nla_len);
if (na->nla_type == NFC_ATTR_TARGET_INDEX)
targetidx = *(int *)((char *)na + NLA_HDRLEN);
else if (na->nla_type == NFC_ATTR_TARGET_SEL_RES)
sel_res = *(__u8 *)((char *)na + NLA_HDRLEN);
else if (na->nla_type == NFC_ATTR_PROTOCOLS)
protocol = *(__u32 *)((char *)na + NLA_HDRLEN);
na = (struct nlattr *)(GENLMSG_DATA(&ans) + len);
}
if (targetidx == -1 || sel_res != 0x20 || protocol != NFC_PROTO_ISO14443_MASK)
return -1;
return targetidx;
}
int connect_socket(int dev_idx, int target_idx)
{
struct sockaddr_nfc addr;
int sock;
int err = 0;
sock = socket(AF_NFC, SOCK_SEQPACKET, NFC_SOCKPROTO_RAW);
if (sock == -1)
return -1;
addr.sa_family = AF_NFC;
addr.dev_idx = dev_idx;
addr.target_idx = target_idx;
addr.nfc_protocol = NFC_PROTO_ISO14443;
err = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
if (err) {
close(sock);
return -1;
}
return sock;
}
int connect_tag(int dev_idx, int virtual_fd, int sd, int fid, int pid)
{
struct genlmsghdr *genlhdr;
struct nlattr *na;
char evt_data[255];
int target_idx;
int resp_len;
int evt_dev;
write(virtual_fd, nci_rf_activate_ntf, sizeof(nci_rf_activate_ntf));
resp_len = recv(sd, evt_data, sizeof(evt_data), 0);
if (resp_len < 0)
return -1;
genlhdr = (struct genlmsghdr *)((struct nlmsghdr *)evt_data + 1);
na = (struct nlattr *)(genlhdr + 1);
evt_dev = *(int *)((char *)na + NLA_HDRLEN);
if (dev_idx != evt_dev)
return -1;
target_idx = get_taginfo(dev_idx, sd, fid, pid);
if (target_idx == -1)
return -1;
return connect_socket(dev_idx, target_idx);
}
int read_write_nci_cmd(int nfc_sock, int virtual_fd, const __u8 *cmd, __u32 cmd_len,
const __u8 *rsp, __u32 rsp_len)
{
char buf[256];
unsigned int len;
send(nfc_sock, &cmd[3], cmd_len - 3, 0);
len = read(virtual_fd, buf, cmd_len);
if (len < 0 || memcmp(buf, cmd, cmd_len))
return -1;
write(virtual_fd, rsp, rsp_len);
len = recv(nfc_sock, buf, rsp_len - 2, 0);
if (len < 0 || memcmp(&buf[1], &rsp[3], rsp_len - 3))
return -1;
return 0;
}
int read_tag(int nfc_sock, int virtual_fd)
{
if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_select_cmd,
sizeof(nci_t4t_select_cmd), nci_t4t_rsp_ok,
sizeof(nci_t4t_rsp_ok)))
return -1;
if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_select_cmd2,
sizeof(nci_t4t_select_cmd2), nci_t4t_rsp_ok,
sizeof(nci_t4t_rsp_ok)))
return -1;
if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_read_cmd,
sizeof(nci_t4t_read_cmd), nci_t4t_read_rsp,
sizeof(nci_t4t_read_rsp)))
return -1;
if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_select_cmd3,
sizeof(nci_t4t_select_cmd3), nci_t4t_rsp_ok,
sizeof(nci_t4t_rsp_ok)))
return -1;
if (read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_read_cmd2,
sizeof(nci_t4t_read_cmd2), nci_t4t_read_rsp2,
sizeof(nci_t4t_read_rsp2)))
return -1;
return read_write_nci_cmd(nfc_sock, virtual_fd, nci_t4t_read_cmd3,
sizeof(nci_t4t_read_cmd3), nci_t4t_read_rsp3,
sizeof(nci_t4t_read_rsp3));
}
static void *virtual_deactivate_proc(void *data)
{
int virtual_fd;
char buf[256];
int deactcmd_len;
int len;
virtual_fd = *(int *)data;
deactcmd_len = sizeof(nci_rf_deact_cmd);
len = read(virtual_fd, buf, deactcmd_len);
if (len != deactcmd_len || memcmp(buf, nci_rf_deact_cmd, deactcmd_len))
return (void *)-1;
write(virtual_fd, nci_rf_deact_rsp, sizeof(nci_rf_deact_rsp));
write(virtual_fd, nci_rf_deact_ntf, sizeof(nci_rf_deact_ntf));
return (void *)0;
}
int disconnect_tag(int nfc_sock, int virtual_fd)
{
pthread_t thread_t;
char buf[256];
int status;
int len;
send(nfc_sock, &nci_t4t_select_cmd3[3], sizeof(nci_t4t_select_cmd3) - 3, 0);
len = read(virtual_fd, buf, sizeof(nci_t4t_select_cmd3));
if (len < 0 || memcmp(buf, nci_t4t_select_cmd3, sizeof(nci_t4t_select_cmd3)))
return -1;
len = recv(nfc_sock, buf, sizeof(nci_t4t_rsp_ok), 0);
if (len != -1)
return -1;
status = pthread_create(&thread_t, NULL, virtual_deactivate_proc,
(void *)&virtual_fd);
close(nfc_sock);
pthread_join(thread_t, (void **)&status);
return status;
}
TEST_F(NCI, t4t_tag_read)
{
int nfc_sock;
int status;
status = start_polling(self->dev_idex, self->proto, self->virtual_nci_fd,
self->sd, self->fid, self->pid);
EXPECT_EQ(status, 0);
nfc_sock = connect_tag(self->dev_idex, self->virtual_nci_fd, self->sd,
self->fid, self->pid);
ASSERT_GT(nfc_sock, -1);
status = read_tag(nfc_sock, self->virtual_nci_fd);
ASSERT_EQ(status, 0);
status = disconnect_tag(nfc_sock, self->virtual_nci_fd);
EXPECT_EQ(status, 0);
}
TEST_F(NCI, deinit)
{
struct msgtemplate msg;
pthread_t thread_t;
int status;
int rc;
rc = get_nci_devid(self->sd, self->fid, self->pid, self->dev_idex,
&msg);
ASSERT_EQ(rc, 0);
EXPECT_EQ(get_dev_enable_state(&msg), 1);
if (self->isNCI2)
rc = pthread_create(&thread_t, NULL, virtual_deinit_v2,
(void *)&self->virtual_nci_fd);
else
rc = pthread_create(&thread_t, NULL, virtual_deinit,
(void *)&self->virtual_nci_fd);
ASSERT_GT(rc, -1);
rc = send_cmd_with_idx(self->sd, self->fid, self->pid,
NFC_CMD_DEV_DOWN, self->dev_idex);
EXPECT_EQ(rc, 0);
pthread_join(thread_t, (void **)&status);
self->open_state = 0;
ASSERT_EQ(status, 0);
rc = get_nci_devid(self->sd, self->fid, self->pid, self->dev_idex,
&msg);
ASSERT_EQ(rc, 0);
EXPECT_EQ(get_dev_enable_state(&msg), 0);
}
TEST_HARNESS_MAIN