From c45e3e4c5b134b081e8af362109905427967eb19 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 9 Jul 2017 13:08:58 +0200 Subject: [PATCH 01/14] NFC: fix device-allocation error return A recent change fixing NFC device allocation itself introduced an error-handling bug by returning an error pointer in case device-id allocation failed. This is clearly broken as the callers still expected NULL to be returned on errors as detected by Dan's static checker. Fix this up by returning NULL in the event that we've run out of memory when allocating a new device id. Note that the offending commit is marked for stable (3.8) so this fix needs to be backported along with it. Fixes: 20777bc57c34 ("NFC: fix broken device allocation") Cc: stable # 3.8 Reported-by: Dan Carpenter Signed-off-by: Johan Hovold Signed-off-by: Samuel Ortiz --- net/nfc/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/nfc/core.c b/net/nfc/core.c index e5e23c2cbe74..2c7c9b357e70 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -1105,7 +1105,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, err_free_dev: kfree(dev); - return ERR_PTR(rc); + return NULL; } EXPORT_SYMBOL(nfc_allocate_device); From f98bc10e0eb90075665516c6ddc81761d42b3525 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 21 Aug 2017 22:33:53 +0530 Subject: [PATCH 02/14] nfc: microread: constify i2c_device_id i2c_device_id are not supposed to change at runtime. All functions working with i2c_device_id provided by work with const i2c_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Samuel Ortiz --- drivers/nfc/microread/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c index b668b7b9a61e..1806d20a5e29 100644 --- a/drivers/nfc/microread/i2c.c +++ b/drivers/nfc/microread/i2c.c @@ -294,7 +294,7 @@ static int microread_i2c_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id microread_i2c_id[] = { +static const struct i2c_device_id microread_i2c_id[] = { { MICROREAD_I2C_DRIVER_NAME, 0}, { } }; From ab1df981574bdb06c2d7f8b6817d5007c2f4a10d Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 21 Aug 2017 22:33:54 +0530 Subject: [PATCH 03/14] nfc: nfcmrvl: constify i2c_device_id i2c_device_id are not supposed to change at runtime. All functions working with i2c_device_id provided by work with const i2c_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcmrvl/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/nfcmrvl/i2c.c b/drivers/nfc/nfcmrvl/i2c.c index ffec103702f1..0f22379887ca 100644 --- a/drivers/nfc/nfcmrvl/i2c.c +++ b/drivers/nfc/nfcmrvl/i2c.c @@ -266,7 +266,7 @@ static const struct of_device_id of_nfcmrvl_i2c_match[] = { }; MODULE_DEVICE_TABLE(of, of_nfcmrvl_i2c_match); -static struct i2c_device_id nfcmrvl_i2c_id_table[] = { +static const struct i2c_device_id nfcmrvl_i2c_id_table[] = { { "nfcmrvl_i2c", 0 }, {} }; From 01e682ad085d0e7d253c3bad557a2a4b08bbf5fe Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 21 Aug 2017 22:33:55 +0530 Subject: [PATCH 04/14] nfc: nxp-nci: constify i2c_device_id i2c_device_id are not supposed to change at runtime. All functions working with i2c_device_id provided by work with const i2c_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Samuel Ortiz --- drivers/nfc/nxp-nci/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c index 198585bbc771..ba695e392c3b 100644 --- a/drivers/nfc/nxp-nci/i2c.c +++ b/drivers/nfc/nxp-nci/i2c.c @@ -393,7 +393,7 @@ static int nxp_nci_i2c_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id nxp_nci_i2c_id_table[] = { +static const struct i2c_device_id nxp_nci_i2c_id_table[] = { {"nxp-nci_i2c", 0}, {} }; From f98786da9d18ee1ecfac4a68e532b1859cf7d1c0 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 21 Aug 2017 22:33:56 +0530 Subject: [PATCH 05/14] nfc: pn533: constify i2c_device_id i2c_device_id are not supposed to change at runtime. All functions working with i2c_device_id provided by work with const i2c_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Samuel Ortiz --- drivers/nfc/pn533/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c index 8f60ce039b0d..4389eb4c8d0b 100644 --- a/drivers/nfc/pn533/i2c.c +++ b/drivers/nfc/pn533/i2c.c @@ -264,7 +264,7 @@ static const struct of_device_id of_pn533_i2c_match[] = { }; MODULE_DEVICE_TABLE(of, of_pn533_i2c_match); -static struct i2c_device_id pn533_i2c_id_table[] = { +static const struct i2c_device_id pn533_i2c_id_table[] = { { PN533_I2C_DRIVER_NAME, 0 }, {} }; From 3737ff15b0e88fd9d4942118c2c9ece917ddc68f Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 21 Aug 2017 22:33:57 +0530 Subject: [PATCH 06/14] nfc: pn544: constify i2c_device_id i2c_device_id are not supposed to change at runtime. All functions working with i2c_device_id provided by work with const i2c_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index 4b14740edb67..d0207f8e68b7 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -54,7 +54,7 @@ #define PN544_HCI_I2C_LLC_MAX_SIZE (PN544_HCI_I2C_LLC_LEN_CRC + 1 + \ PN544_HCI_I2C_LLC_MAX_PAYLOAD) -static struct i2c_device_id pn544_hci_i2c_id_table[] = { +static const struct i2c_device_id pn544_hci_i2c_id_table[] = { {"pn544", 0}, {} }; From 81251cc599acfac63d68caa69c6284b546c66fe0 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 21 Aug 2017 22:33:58 +0530 Subject: [PATCH 07/14] nfc: s3fwrn5: constify i2c_device_id i2c_device_id are not supposed to change at runtime. All functions working with i2c_device_id provided by work with const i2c_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Samuel Ortiz --- drivers/nfc/s3fwrn5/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/s3fwrn5/i2c.c b/drivers/nfc/s3fwrn5/i2c.c index 3f09d7fd2285..4da409e77a72 100644 --- a/drivers/nfc/s3fwrn5/i2c.c +++ b/drivers/nfc/s3fwrn5/i2c.c @@ -276,7 +276,7 @@ static int s3fwrn5_i2c_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id s3fwrn5_i2c_id_table[] = { +static const struct i2c_device_id s3fwrn5_i2c_id_table[] = { {S3FWRN5_I2C_DRIVER_NAME, 0}, {} }; From 984553078497082008b8a2bd681facdc789b5acf Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 21 Aug 2017 22:33:59 +0530 Subject: [PATCH 08/14] nfc: st-nci: constify i2c_device_id i2c_device_id are not supposed to change at runtime. All functions working with i2c_device_id provided by work with const i2c_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Samuel Ortiz --- drivers/nfc/st-nci/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 515f08d037fb..f9525ef87d57 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -279,7 +279,7 @@ static int st_nci_i2c_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id st_nci_i2c_id_table[] = { +static const struct i2c_device_id st_nci_i2c_id_table[] = { {ST_NCI_DRIVER_NAME, 0}, {} }; From a122ffd0911d563f4b5e95120259ec5d2e8e3c4f Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 21 Aug 2017 22:34:00 +0530 Subject: [PATCH 09/14] nfc: st21nfca: constify i2c_device_id i2c_device_id are not supposed to change at runtime. All functions working with i2c_device_id provided by work with const i2c_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Samuel Ortiz --- drivers/nfc/st21nfca/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index cd1f7bfa75eb..1b347096422f 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -589,7 +589,7 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id st21nfca_hci_i2c_id_table[] = { +static const struct i2c_device_id st21nfca_hci_i2c_id_table[] = { {ST21NFCA_HCI_DRIVER_NAME, 0}, {} }; From 5057f6647b3286eee2d9a7eff7f3c072ea7573d9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 19 Sep 2017 15:25:15 +0100 Subject: [PATCH 10/14] nfc: s3fwrn5: make array match static const Don't populate the read-only array match on the stack, instead make it static const. Makes the object code smaller by over 310 bytes: Before: text data bss dec hex filename 8304 1084 128 9516 252c drivers/nfc/s3fwrn5/firmware.o After: text data bss dec hex filename 7894 1180 128 9202 23f2 drivers/nfc/s3fwrn5/firmware.o Signed-off-by: Colin Ian King Signed-off-by: Samuel Ortiz --- drivers/nfc/s3fwrn5/firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/s3fwrn5/firmware.c b/drivers/nfc/s3fwrn5/firmware.c index 38548bd970cd..b7828fb252f2 100644 --- a/drivers/nfc/s3fwrn5/firmware.c +++ b/drivers/nfc/s3fwrn5/firmware.c @@ -336,7 +336,7 @@ static int s3fwrn5_fw_get_base_addr( struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo, u32 *base_addr) { int i; - struct { + static const struct { u8 version[4]; u32 base_addr; } match[] = { From 81ade1cd6761e791904801ca9bfc960de4b94916 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 5 Oct 2017 10:47:12 +0100 Subject: [PATCH 11/14] NFC: fdp: make struct nci_ops static The structure nci_ops is local to the source and does not need to be in global scope, so make it static. Cleans up sparse warning: symbol 'nci_ops' was not declared. Should it be static? Signed-off-by: Colin Ian King Signed-off-by: Samuel Ortiz --- drivers/nfc/fdp/fdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/fdp/fdp.c b/drivers/nfc/fdp/fdp.c index ec50027b0d8b..d5784a47fc13 100644 --- a/drivers/nfc/fdp/fdp.c +++ b/drivers/nfc/fdp/fdp.c @@ -726,7 +726,7 @@ static struct nci_driver_ops fdp_prop_ops[] = { }, }; -struct nci_ops nci_ops = { +static struct nci_ops nci_ops = { .open = fdp_nci_open, .close = fdp_nci_close, .send = fdp_nci_send, From 4b519bb493e0866de7659b88dd22dc2cd89dd628 Mon Sep 17 00:00:00 2001 From: Allen Pais Date: Wed, 11 Oct 2017 16:03:44 +0530 Subject: [PATCH 12/14] NFC: Convert timers to use timer_setup() Switch to using the new timer_setup() and from_timer() for net/nfc/* Signed-off-by: Allen Pais Reviewed-by: Kees Cook Signed-off-by: Samuel Ortiz --- net/nfc/core.c | 8 +++----- net/nfc/hci/core.c | 7 +++---- net/nfc/hci/llc_shdlc.c | 23 +++++++++-------------- net/nfc/llcp_core.c | 14 ++++++-------- 4 files changed, 21 insertions(+), 31 deletions(-) diff --git a/net/nfc/core.c b/net/nfc/core.c index 2c7c9b357e70..947a470f929d 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -1015,9 +1015,9 @@ exit: device_unlock(&dev->dev); } -static void nfc_check_pres_timeout(unsigned long data) +static void nfc_check_pres_timeout(struct timer_list *t) { - struct nfc_dev *dev = (struct nfc_dev *)data; + struct nfc_dev *dev = from_timer(dev, t, check_pres_timer); schedule_work(&dev->check_pres_work); } @@ -1094,9 +1094,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, dev->targets_generation = 1; if (ops->check_presence) { - setup_timer(&dev->check_pres_timer, nfc_check_pres_timeout, - (unsigned long)dev); - + timer_setup(&dev->check_pres_timer, nfc_check_pres_timeout, 0); INIT_WORK(&dev->check_pres_work, nfc_check_pres_work); } diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index a8a6e7814e09..ac8030c4bcf8 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -428,9 +428,9 @@ exit_noskb: nfc_hci_driver_failure(hdev, r); } -static void nfc_hci_cmd_timeout(unsigned long data) +static void nfc_hci_cmd_timeout(struct timer_list *t) { - struct nfc_hci_dev *hdev = (struct nfc_hci_dev *)data; + struct nfc_hci_dev *hdev = from_timer(hdev, t, cmd_timer); schedule_work(&hdev->msg_tx_work); } @@ -1004,8 +1004,7 @@ int nfc_hci_register_device(struct nfc_hci_dev *hdev) INIT_WORK(&hdev->msg_tx_work, nfc_hci_msg_tx_work); - setup_timer(&hdev->cmd_timer, nfc_hci_cmd_timeout, - (unsigned long)hdev); + timer_setup(&hdev->cmd_timer, nfc_hci_cmd_timeout, 0); skb_queue_head_init(&hdev->rx_hcp_frags); diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c index 58df37eae1e8..fe988936ad92 100644 --- a/net/nfc/hci/llc_shdlc.c +++ b/net/nfc/hci/llc_shdlc.c @@ -580,27 +580,27 @@ static void llc_shdlc_handle_send_queue(struct llc_shdlc *shdlc) } } -static void llc_shdlc_connect_timeout(unsigned long data) +static void llc_shdlc_connect_timeout(struct timer_list *t) { - struct llc_shdlc *shdlc = (struct llc_shdlc *)data; + struct llc_shdlc *shdlc = from_timer(shdlc, t, connect_timer); pr_debug("\n"); schedule_work(&shdlc->sm_work); } -static void llc_shdlc_t1_timeout(unsigned long data) +static void llc_shdlc_t1_timeout(struct timer_list *t) { - struct llc_shdlc *shdlc = (struct llc_shdlc *)data; + struct llc_shdlc *shdlc = from_timer(shdlc, t, t1_timer); pr_debug("SoftIRQ: need to send ack\n"); schedule_work(&shdlc->sm_work); } -static void llc_shdlc_t2_timeout(unsigned long data) +static void llc_shdlc_t2_timeout(struct timer_list *t) { - struct llc_shdlc *shdlc = (struct llc_shdlc *)data; + struct llc_shdlc *shdlc = from_timer(shdlc, t, t2_timer); pr_debug("SoftIRQ: need to retransmit\n"); @@ -763,14 +763,9 @@ static void *llc_shdlc_init(struct nfc_hci_dev *hdev, xmit_to_drv_t xmit_to_drv, mutex_init(&shdlc->state_mutex); shdlc->state = SHDLC_DISCONNECTED; - setup_timer(&shdlc->connect_timer, llc_shdlc_connect_timeout, - (unsigned long)shdlc); - - setup_timer(&shdlc->t1_timer, llc_shdlc_t1_timeout, - (unsigned long)shdlc); - - setup_timer(&shdlc->t2_timer, llc_shdlc_t2_timeout, - (unsigned long)shdlc); + timer_setup(&shdlc->connect_timer, llc_shdlc_connect_timeout, 0); + timer_setup(&shdlc->t1_timer, llc_shdlc_t1_timeout, 0); + timer_setup(&shdlc->t2_timer, llc_shdlc_t2_timeout, 0); shdlc->w = SHDLC_MAX_WINDOW; shdlc->srej_support = SHDLC_SREJ_SUPPORT; diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index 7988185072e5..ef4026a23e80 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -242,9 +242,9 @@ static void nfc_llcp_timeout_work(struct work_struct *work) nfc_dep_link_down(local->dev); } -static void nfc_llcp_symm_timer(unsigned long data) +static void nfc_llcp_symm_timer(struct timer_list *t) { - struct nfc_llcp_local *local = (struct nfc_llcp_local *) data; + struct nfc_llcp_local *local = from_timer(local, t, link_timer); pr_err("SYMM timeout\n"); @@ -285,9 +285,9 @@ static void nfc_llcp_sdreq_timeout_work(struct work_struct *work) nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list); } -static void nfc_llcp_sdreq_timer(unsigned long data) +static void nfc_llcp_sdreq_timer(struct timer_list *t) { - struct nfc_llcp_local *local = (struct nfc_llcp_local *) data; + struct nfc_llcp_local *local = from_timer(local, t, sdreq_timer); schedule_work(&local->sdreq_timeout_work); } @@ -1573,8 +1573,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) INIT_LIST_HEAD(&local->list); kref_init(&local->ref); mutex_init(&local->sdp_lock); - setup_timer(&local->link_timer, nfc_llcp_symm_timer, - (unsigned long)local); + timer_setup(&local->link_timer, nfc_llcp_symm_timer, 0); skb_queue_head_init(&local->tx_queue); INIT_WORK(&local->tx_work, nfc_llcp_tx_work); @@ -1600,8 +1599,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) mutex_init(&local->sdreq_lock); INIT_HLIST_HEAD(&local->pending_sdreqs); - setup_timer(&local->sdreq_timer, nfc_llcp_sdreq_timer, - (unsigned long)local); + timer_setup(&local->sdreq_timer, nfc_llcp_sdreq_timer, 0); INIT_WORK(&local->sdreq_timeout_work, nfc_llcp_sdreq_timeout_work); list_add(&local->list, &llcp_devices); From 72ad533acc22870156736c2fef4674c01307695e Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Thu, 15 Jun 2017 20:34:21 -0700 Subject: [PATCH 13/14] NFC: digital: Abort cmd when deactivating target When deactivating an active target, the outstanding command should be aborted. Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- net/nfc/digital_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index de6dd37d04c7..ec0a8998e52d 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c @@ -650,6 +650,7 @@ static void digital_deactivate_target(struct nfc_dev *nfc_dev, return; } + digital_abort_cmd(ddev); ddev->curr_protocol = 0; } From 4d63adfe12dd9cb61ed8badb4d798955399048c2 Mon Sep 17 00:00:00 2001 From: Mark Greer Date: Thu, 15 Jun 2017 20:34:22 -0700 Subject: [PATCH 14/14] NFC: Add NFC_CMD_DEACTIVATE_TARGET support Once an NFC target (i.e., a tag) is found, it remains active until there is a failure reading or writing it (often caused by the target moving out of range). While the target is active, the NFC adapter and antenna must remain powered. This wastes power when the target remains in range but the client application no longer cares whether it is there or not. To mitigate this, add a new netlink command that allows userspace to deactivate an active target. When issued, this command will cause the NFC subsystem to act as though the target was moved out of range. Once the command has been executed, the client application can power off the NFC adapter to reduce power consumption. Signed-off-by: Mark Greer Signed-off-by: Samuel Ortiz --- include/uapi/linux/nfc.h | 2 ++ net/nfc/netlink.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h index 399f39ff8048..f6e3c8c9c744 100644 --- a/include/uapi/linux/nfc.h +++ b/include/uapi/linux/nfc.h @@ -89,6 +89,7 @@ * @NFC_CMD_ACTIVATE_TARGET: Request NFC controller to reactivate target. * @NFC_CMD_VENDOR: Vendor specific command, to be implemented directly * from the driver in order to support hardware specific operations. + * @NFC_CMD_DEACTIVATE_TARGET: Request NFC controller to deactivate target. */ enum nfc_commands { NFC_CMD_UNSPEC, @@ -121,6 +122,7 @@ enum nfc_commands { NFC_CMD_SE_IO, NFC_CMD_ACTIVATE_TARGET, NFC_CMD_VENDOR, + NFC_CMD_DEACTIVATE_TARGET, /* private: internal use only */ __NFC_CMD_AFTER_LAST }; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index b251fb936a27..f6359c277212 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -928,6 +928,30 @@ static int nfc_genl_activate_target(struct sk_buff *skb, struct genl_info *info) return rc; } +static int nfc_genl_deactivate_target(struct sk_buff *skb, + struct genl_info *info) +{ + struct nfc_dev *dev; + u32 device_idx, target_idx; + int rc; + + if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) + return -EINVAL; + + device_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); + + dev = nfc_get_device(device_idx); + if (!dev) + return -ENODEV; + + target_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]); + + rc = nfc_deactivate_target(dev, target_idx, NFC_TARGET_MODE_SLEEP); + + nfc_put_device(dev); + return rc; +} + static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info) { struct nfc_dev *dev; @@ -1751,6 +1775,11 @@ static const struct genl_ops nfc_genl_ops[] = { .doit = nfc_genl_vendor_cmd, .policy = nfc_genl_policy, }, + { + .cmd = NFC_CMD_DEACTIVATE_TARGET, + .doit = nfc_genl_deactivate_target, + .policy = nfc_genl_policy, + }, }; static struct genl_family nfc_genl_family __ro_after_init = {