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>
This commit is contained in:
Bongsu Jeon 2021-08-17 06:28:18 -07:00 коммит произвёл David S. Miller
Родитель 72696bd8a0
Коммит 61612511e5
1 изменённых файлов: 287 добавлений и 5 удалений

Просмотреть файл

@ -57,6 +57,29 @@ const __u8 nci_init_rsp_v2[] = {0x40, 0x01, 0x1c, 0x00, 0x1a, 0x7e, 0x06,
const __u8 nci_rf_disc_map_rsp[] = {0x41, 0x00, 0x01, 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_disc_rsp[] = {0x41, 0x03, 0x01, 0x00};
const __u8 nci_rf_deact_rsp[] = {0x41, 0x06, 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 msgtemplate {
struct nlmsghdr n; struct nlmsghdr n;
@ -150,7 +173,7 @@ static int send_get_nfc_family(int sd, __u32 pid)
&nla_get_family_len, NLM_F_REQUEST); &nla_get_family_len, NLM_F_REQUEST);
} }
static int get_family_id(int sd, __u32 pid) static int get_family_id(int sd, __u32 pid, __u32 *event_group)
{ {
struct { struct {
struct nlmsghdr n; struct nlmsghdr n;
@ -160,6 +183,7 @@ static int get_family_id(int sd, __u32 pid)
struct nlattr *na; struct nlattr *na;
int resp_len; int resp_len;
__u16 id; __u16 id;
int len;
int rc; int rc;
rc = send_get_nfc_family(sd, pid); rc = send_get_nfc_family(sd, pid);
@ -173,11 +197,43 @@ static int get_family_id(int sd, __u32 pid)
!NLMSG_OK(&ans.n, resp_len)) !NLMSG_OK(&ans.n, resp_len))
return 0; return 0;
len = 0;
resp_len = GENLMSG_PAYLOAD(&ans.n);
na = (struct nlattr *)GENLMSG_DATA(&ans); na = (struct nlattr *)GENLMSG_DATA(&ans);
na = (struct nlattr *)((char *)na + NLA_ALIGN(na->nla_len));
if (na->nla_type == CTRL_ATTR_FAMILY_ID)
id = *(__u16 *)NLA_DATA(na);
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; return id;
} }
@ -347,6 +403,7 @@ FIXTURE_SETUP(NCI)
{ {
struct msgtemplate msg; struct msgtemplate msg;
pthread_t thread_t; pthread_t thread_t;
__u32 event_group;
int status; int status;
int rc; int rc;
@ -358,12 +415,16 @@ FIXTURE_SETUP(NCI)
ASSERT_NE(self->sd, -1); ASSERT_NE(self->sd, -1);
self->pid = getpid(); self->pid = getpid();
self->fid = get_family_id(self->sd, self->pid); self->fid = get_family_id(self->sd, self->pid, &event_group);
ASSERT_NE(self->fid, -1); ASSERT_NE(self->fid, -1);
self->virtual_nci_fd = open("/dev/virtual_nci", O_RDWR); self->virtual_nci_fd = open("/dev/virtual_nci", O_RDWR);
ASSERT_GT(self->virtual_nci_fd, -1); 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); rc = ioctl(self->virtual_nci_fd, IOCTL_GET_NCIDEV_IDX, &self->dev_idex);
ASSERT_EQ(rc, 0); ASSERT_EQ(rc, 0);
@ -574,6 +635,227 @@ TEST_F(NCI, start_poll)
EXPECT_EQ(status, 0); 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) TEST_F(NCI, deinit)
{ {
struct msgtemplate msg; struct msgtemplate msg;