From 390a1bd8538132186ddb679cafe9e75b7ef7e2d2 Mon Sep 17 00:00:00 2001
From: Samuel Ortiz <sameo@linux.intel.com>
Date: Wed, 19 Dec 2012 19:11:32 +0100
Subject: [PATCH] NFC: Initial Secure Element API

Each NFC adapter can have several links to different secure elements and
that property needs to be exported by the drivers.
A secure element link can be enabled and disabled, and card emulation will
be handled by the currently active one. Otherwise card emulation will be
host implemented.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/nfc/nfcwilink.c    |  1 +
 drivers/nfc/pn533.c        |  1 +
 drivers/nfc/pn544/pn544.c  |  6 ++++--
 include/net/nfc/hci.h      |  3 +++
 include/net/nfc/nci_core.h |  1 +
 include/net/nfc/nfc.h      |  6 ++++++
 include/uapi/linux/nfc.h   | 14 ++++++++++++++
 net/nfc/core.c             |  3 +++
 net/nfc/hci/core.c         |  3 ++-
 net/nfc/nci/core.c         |  2 ++
 net/nfc/netlink.c          |  1 +
 11 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c
index c7c182d2b7df..3b731acbc408 100644
--- a/drivers/nfc/nfcwilink.c
+++ b/drivers/nfc/nfcwilink.c
@@ -542,6 +542,7 @@ static int nfcwilink_probe(struct platform_device *pdev)
 
 	drv->ndev = nci_allocate_device(&nfcwilink_ops,
 					protocols,
+					NFC_SE_NONE,
 					NFCWILINK_HDR_LEN,
 					0);
 	if (!drv->ndev) {
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index e8c083203b33..31a5b3b53b2a 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -2525,6 +2525,7 @@ static int pn533_probe(struct usb_interface *interface,
 
 
 	dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
+					   NFC_SE_NONE,
 					   dev->ops->tx_header_len +
 					   PN533_CMD_DATAEXCH_HEAD_LEN,
 					   dev->ops->tx_tail_len);
diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c
index d108c794008d..9c5f16e7baef 100644
--- a/drivers/nfc/pn544/pn544.c
+++ b/drivers/nfc/pn544/pn544.c
@@ -801,7 +801,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
 		    struct nfc_hci_dev **hdev)
 {
 	struct pn544_hci_info *info;
-	u32 protocols;
+	u32 protocols, se;
 	struct nfc_hci_init_data init_data;
 	int r;
 
@@ -834,8 +834,10 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
 		    NFC_PROTO_ISO14443_B_MASK |
 		    NFC_PROTO_NFC_DEP_MASK;
 
+	se = NFC_SE_UICC | NFC_SE_EMBEDDED;
+
 	info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
-					     protocols, llc_name,
+					     protocols, se, llc_name,
 					     phy_headroom + PN544_CMDS_HEADROOM,
 					     phy_tailroom, phy_payload);
 	if (!info->hdev) {
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h
index 2ff71750c428..b87a1692b086 100644
--- a/include/net/nfc/hci.h
+++ b/include/net/nfc/hci.h
@@ -59,6 +59,8 @@ struct nfc_hci_ops {
 			      struct nfc_target *target);
 	int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
 			      struct sk_buff *skb);
+	int (*enable_se)(struct nfc_dev *dev, u32 secure_element);
+	int (*disable_se)(struct nfc_dev *dev, u32 secure_element);
 };
 
 /* Pipes */
@@ -150,6 +152,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
 					    struct nfc_hci_init_data *init_data,
 					    unsigned long quirks,
 					    u32 protocols,
+					    u32 supported_se,
 					    const char *llc_name,
 					    int tx_headroom,
 					    int tx_tailroom,
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
index d705d8674949..5bc0c460edc0 100644
--- a/include/net/nfc/nci_core.h
+++ b/include/net/nfc/nci_core.h
@@ -147,6 +147,7 @@ struct nci_dev {
 /* ----- NCI Devices ----- */
 struct nci_dev *nci_allocate_device(struct nci_ops *ops,
 				    __u32 supported_protocols,
+				    __u32 supported_se,
 				    int tx_headroom,
 				    int tx_tailroom);
 void nci_free_device(struct nci_dev *ndev);
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 1665674e86b2..87a6417fc934 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -68,6 +68,8 @@ struct nfc_ops {
 			     void *cb_context);
 	int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
 	int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
+	int (*enable_se)(struct nfc_dev *dev, u32 secure_element);
+	int (*disable_se)(struct nfc_dev *dev, u32 secure_element);
 };
 
 #define NFC_TARGET_IDX_ANY -1
@@ -109,6 +111,9 @@ struct nfc_dev {
 	struct nfc_genl_data genl_data;
 	u32 supported_protocols;
 
+	u32 supported_se;
+	u32 active_se;
+
 	int tx_headroom;
 	int tx_tailroom;
 
@@ -125,6 +130,7 @@ extern struct class nfc_class;
 
 struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
 				    u32 supported_protocols,
+				    u32 supported_se,
 				    int tx_headroom,
 				    int tx_tailroom);
 
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h
index 0e63cee8d810..80e4ecd8c04c 100644
--- a/include/uapi/linux/nfc.h
+++ b/include/uapi/linux/nfc.h
@@ -67,6 +67,11 @@
  *	subsequent CONNECT and CC messages.
  *	If one of the passed parameters is wrong none is set and -EINVAL is
  *	returned.
+ * @NFC_CMD_ENABLE_SE: Enable the physical link to a specific secure element.
+ *	Once enabled a secure element will handle card emulation mode, i.e.
+ *	starting a poll from a device which has a secure element enabled means
+ *	we want to do SE based card emulation.
+ * @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element.
  */
 enum nfc_commands {
 	NFC_CMD_UNSPEC,
@@ -86,6 +91,8 @@ enum nfc_commands {
 	NFC_EVENT_TM_DEACTIVATED,
 	NFC_CMD_LLC_GET_PARAMS,
 	NFC_CMD_LLC_SET_PARAMS,
+	NFC_CMD_ENABLE_SE,
+	NFC_CMD_DISABLE_SE,
 /* private: internal use only */
 	__NFC_CMD_AFTER_LAST
 };
@@ -114,6 +121,7 @@ enum nfc_commands {
  * @NFC_ATTR_LLC_PARAM_LTO: Link TimeOut parameter
  * @NFC_ATTR_LLC_PARAM_RW: Receive Window size parameter
  * @NFC_ATTR_LLC_PARAM_MIUX: MIU eXtension parameter
+ * @NFC_ATTR_SE: Available Secure Elements
  */
 enum nfc_attrs {
 	NFC_ATTR_UNSPEC,
@@ -134,6 +142,7 @@ enum nfc_attrs {
 	NFC_ATTR_LLC_PARAM_LTO,
 	NFC_ATTR_LLC_PARAM_RW,
 	NFC_ATTR_LLC_PARAM_MIUX,
+	NFC_ATTR_SE,
 /* private: internal use only */
 	__NFC_ATTR_AFTER_LAST
 };
@@ -172,6 +181,11 @@ enum nfc_attrs {
 #define NFC_PROTO_NFC_DEP_MASK	  (1 << NFC_PROTO_NFC_DEP)
 #define NFC_PROTO_ISO14443_B_MASK (1 << NFC_PROTO_ISO14443_B)
 
+/* NFC Secure Elements */
+#define NFC_SE_NONE     0x0
+#define NFC_SE_UICC     0x1
+#define NFC_SE_EMBEDDED 0x2
+
 struct sockaddr_nfc {
 	sa_family_t sa_family;
 	__u32 dev_idx;
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 7d7b4ee34015..25522e56d350 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -757,6 +757,7 @@ struct nfc_dev *nfc_get_device(unsigned int idx)
  */
 struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
 				    u32 supported_protocols,
+				    u32 supported_se,
 				    int tx_headroom, int tx_tailroom)
 {
 	struct nfc_dev *dev;
@@ -774,6 +775,8 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
 
 	dev->ops = ops;
 	dev->supported_protocols = supported_protocols;
+	dev->supported_se = supported_se;
+	dev->active_se = NFC_SE_NONE;
 	dev->tx_headroom = tx_headroom;
 	dev->tx_tailroom = tx_tailroom;
 
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 755a6b9774ab..91020b210d87 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -797,6 +797,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
 					    struct nfc_hci_init_data *init_data,
 					    unsigned long quirks,
 					    u32 protocols,
+					    u32 supported_se,
 					    const char *llc_name,
 					    int tx_headroom,
 					    int tx_tailroom,
@@ -822,7 +823,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
 		return NULL;
 	}
 
-	hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols,
+	hdev->ndev = nfc_allocate_device(&hci_nfc_ops, protocols, supported_se,
 					 tx_headroom + HCI_CMDS_HEADROOM,
 					 tx_tailroom);
 	if (!hdev->ndev) {
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 5f98dc1bf039..48ada0ec749e 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -658,6 +658,7 @@ static struct nfc_ops nci_nfc_ops = {
  */
 struct nci_dev *nci_allocate_device(struct nci_ops *ops,
 				    __u32 supported_protocols,
+				    __u32 supported_se,
 				    int tx_headroom, int tx_tailroom)
 {
 	struct nci_dev *ndev;
@@ -680,6 +681,7 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops,
 
 	ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops,
 					    supported_protocols,
+					    supported_se,
 					    tx_headroom + NCI_DATA_HDR_SIZE,
 					    tx_tailroom);
 	if (!ndev->nfc_dev)
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 3568ae16786d..504b883439f1 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -366,6 +366,7 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
 	if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||
 	    nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
 	    nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) ||
+	    nla_put_u32(msg, NFC_ATTR_SE, dev->supported_se) ||
 	    nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||
 	    nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))
 		goto nla_put_failure;
-- 
GitLab