Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: nfc: Propagate ISO14443 type A target ATS to userspace via netlink

Add a 20-byte field ats to struct nfc_target and expose it as
NFC_ATTR_TARGET_ATS via the netlink interface. The payload contains
'historical bytes' that help to distinguish cards from one another.
The information is commonly used to assemble an emulated ATR similar
to that reported by smart cards with contacts.

Add a 20-byte field target_ats to struct nci_dev to hold the payload
obtained in nci_rf_intf_activated_ntf_packet() and copy it to over to
nfc_target.ats in nci_activate_target(). The approach is similar
to the handling of 'general bytes' within ATR_RES.

Replace the hard-coded size of rats_res within struct
activation_params_nfca_poll_iso_dep by the equal constant NFC_ATS_MAXSIZE
now defined in nfc.h

Within NCI, the information corresponds to the 'RATS Response' activation
parameter that omits the initial length byte TL. This loses no
information and is consistent with our handling of SENSB_RES that
also drops the first (constant) byte.

Tested with nxp_nci_i2c on a few type A targets including an
ICAO 9303 compliant passport.

I refrain from the corresponding change to digital_in_recv_ats()
to have the few drivers based on digital.h fill nfc_target.ats,
as I have no way to test it. That class of drivers appear not to set
NFC_ATTR_TARGET_SENSB_RES either. Consider a separate patch to propagate
(all) the parameters.

Signed-off-by: Juraj Šarinay <juraj@sarinay.com>
Link: https://patch.msgid.link/20241103124525.8392-1-juraj@sarinay.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Juraj Šarinay and committed by
Paolo Abeni
9907cda9 dc7c381b

+60 -3
+1 -1
include/net/nfc/nci.h
··· 475 475 #define NCI_OP_RF_INTF_ACTIVATED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x05) 476 476 struct activation_params_nfca_poll_iso_dep { 477 477 __u8 rats_res_len; 478 - __u8 rats_res[20]; 478 + __u8 rats_res[NFC_ATS_MAXSIZE]; 479 479 }; 480 480 481 481 struct activation_params_nfcb_poll_iso_dep {
+4
include/net/nfc/nci_core.h
··· 265 265 /* stored during intf_activated_ntf */ 266 266 __u8 remote_gb[NFC_MAX_GT_LEN]; 267 267 __u8 remote_gb_len; 268 + 269 + /* stored during intf_activated_ntf */ 270 + __u8 target_ats[NFC_ATS_MAXSIZE]; 271 + __u8 target_ats_len; 268 272 }; 269 273 270 274 /* ----- NCI Devices ----- */
+4
include/net/nfc/nfc.h
··· 86 86 * is a type A one. The %sens_res most significant byte must be byte 2 87 87 * as described by the NFC Forum digital specification (i.e. the platform 88 88 * configuration one) while %sens_res least significant byte is byte 1. 89 + * @ats_len: length of Answer To Select in bytes 90 + * @ats: Answer To Select returned by an ISO 14443 Type A target upon activation 89 91 */ 90 92 struct nfc_target { 91 93 u32 idx; ··· 107 105 u8 is_iso15693; 108 106 u8 iso15693_dsfid; 109 107 u8 iso15693_uid[NFC_ISO15693_UID_MAXSIZE]; 108 + u8 ats_len; 109 + u8 ats[NFC_ATS_MAXSIZE]; 110 110 }; 111 111 112 112 /**
+3
include/uapi/linux/nfc.h
··· 164 164 * @NFC_ATTR_VENDOR_SUBCMD: Vendor specific sub command 165 165 * @NFC_ATTR_VENDOR_DATA: Vendor specific data, to be optionally passed 166 166 * to a vendor specific command implementation 167 + * @NFC_ATTR_TARGET_ATS: ISO 14443 type A target Answer To Select 167 168 */ 168 169 enum nfc_attrs { 169 170 NFC_ATTR_UNSPEC, ··· 199 198 NFC_ATTR_VENDOR_ID, 200 199 NFC_ATTR_VENDOR_SUBCMD, 201 200 NFC_ATTR_VENDOR_DATA, 201 + NFC_ATTR_TARGET_ATS, 202 202 /* private: internal use only */ 203 203 __NFC_ATTR_AFTER_LAST 204 204 }; ··· 227 225 #define NFC_GB_MAXSIZE 48 228 226 #define NFC_FIRMWARE_NAME_MAXSIZE 32 229 227 #define NFC_ISO15693_UID_MAXSIZE 8 228 + #define NFC_ATS_MAXSIZE 20 230 229 231 230 /* NFC protocols */ 232 231 #define NFC_PROTO_JEWEL 1
+12 -1
net/nfc/nci/core.c
··· 757 757 } 758 758 EXPORT_SYMBOL(nci_core_conn_close); 759 759 760 + static void nci_set_target_ats(struct nfc_target *target, struct nci_dev *ndev) 761 + { 762 + if (ndev->target_ats_len > 0) { 763 + target->ats_len = ndev->target_ats_len; 764 + memcpy(target->ats, ndev->target_ats, target->ats_len); 765 + } 766 + } 767 + 760 768 static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev) 761 769 { 762 770 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); ··· 947 939 msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT)); 948 940 } 949 941 950 - if (!rc) 942 + if (!rc) { 951 943 ndev->target_active_prot = protocol; 944 + if (protocol == NFC_PROTO_ISO14443) 945 + nci_set_target_ats(target, ndev); 946 + } 952 947 953 948 return rc; 954 949 }
+31 -1
net/nfc/nci/ntf.c
··· 402 402 switch (ntf->activation_rf_tech_and_mode) { 403 403 case NCI_NFC_A_PASSIVE_POLL_MODE: 404 404 nfca_poll = &ntf->activation_params.nfca_poll_iso_dep; 405 - nfca_poll->rats_res_len = min_t(__u8, *data++, 20); 405 + nfca_poll->rats_res_len = min_t(__u8, *data++, NFC_ATS_MAXSIZE); 406 406 pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len); 407 407 if (nfca_poll->rats_res_len > 0) { 408 408 memcpy(nfca_poll->rats_res, ··· 526 526 pr_err("unsupported activation_rf_tech_and_mode 0x%x\n", 527 527 ntf->activation_rf_tech_and_mode); 528 528 return NCI_STATUS_RF_PROTOCOL_ERROR; 529 + } 530 + 531 + return NCI_STATUS_OK; 532 + } 533 + 534 + static int nci_store_ats_nfc_iso_dep(struct nci_dev *ndev, 535 + const struct nci_rf_intf_activated_ntf *ntf) 536 + { 537 + ndev->target_ats_len = 0; 538 + 539 + if (ntf->activation_params_len <= 0) 540 + return NCI_STATUS_OK; 541 + 542 + if (ntf->activation_params.nfca_poll_iso_dep.rats_res_len > NFC_ATS_MAXSIZE) { 543 + pr_debug("ATS too long\n"); 544 + return NCI_STATUS_RF_PROTOCOL_ERROR; 545 + } 546 + 547 + if (ntf->activation_params.nfca_poll_iso_dep.rats_res_len > 0) { 548 + ndev->target_ats_len = ntf->activation_params.nfca_poll_iso_dep.rats_res_len; 549 + memcpy(ndev->target_ats, ntf->activation_params.nfca_poll_iso_dep.rats_res, 550 + ndev->target_ats_len); 529 551 } 530 552 531 553 return NCI_STATUS_OK; ··· 681 659 err = nci_store_general_bytes_nfc_dep(ndev, &ntf); 682 660 if (err != NCI_STATUS_OK) 683 661 pr_err("unable to store general bytes\n"); 662 + } 663 + 664 + /* store ATS to be reported later in nci_activate_target */ 665 + if (ntf.rf_interface == NCI_RF_INTERFACE_ISO_DEP && 666 + ntf.activation_rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) { 667 + err = nci_store_ats_nfc_iso_dep(ndev, &ntf); 668 + if (err != NCI_STATUS_OK) 669 + pr_err("unable to store ATS\n"); 684 670 } 685 671 } 686 672
+5
net/nfc/netlink.c
··· 96 96 goto nla_put_failure; 97 97 } 98 98 99 + if (target->ats_len > 0 && 100 + nla_put(msg, NFC_ATTR_TARGET_ATS, target->ats_len, 101 + target->ats)) 102 + goto nla_put_failure; 103 + 99 104 genlmsg_end(msg, hdr); 100 105 return 0; 101 106