NFC: Add a GET_SE netlink API
authorSamuel Ortiz <sameo@linux.intel.com>
Wed, 24 Jul 2013 16:10:50 +0000 (18:10 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Tue, 13 Aug 2013 22:35:19 +0000 (00:35 +0200)
In order to fetch the discovered secure elements from an NFC controller,
we need to send a netlink command that will dump the list of available
SEs from NFC.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
include/uapi/linux/nfc.h
net/nfc/netlink.c

index 539d60494c041eff867a36b2b0ba6998e5fd0cac..029921b067fd3e7c0082d60a10951ea53e444fec 100644 (file)
@@ -84,6 +84,7 @@
  * @NFC_EVENT_SE_TRANSACTION: This event is sent when an application running on
  *     a specific SE notifies us about the end of a transaction. The parameter
  *     for this event is the application ID (AID).
+ * @NFC_CMD_GET_SE: Dump all discovered secure elements from an NFC controller.
  */
 enum nfc_commands {
        NFC_CMD_UNSPEC,
@@ -112,6 +113,7 @@ enum nfc_commands {
        NFC_EVENT_SE_REMOVED,
        NFC_EVENT_SE_CONNECTIVITY,
        NFC_EVENT_SE_TRANSACTION,
+       NFC_CMD_GET_SE,
 /* private: internal use only */
        __NFC_CMD_AFTER_LAST
 };
index f16fd59d41607d80aeeae916ae3d43153a0a5b4e..3b08ef90e0451b258cdc58e8c58985aeeee3bc17 100644 (file)
@@ -1191,6 +1191,91 @@ static int nfc_genl_disable_se(struct sk_buff *skb, struct genl_info *info)
        return rc;
 }
 
+static int nfc_genl_send_se(struct sk_buff *msg, struct nfc_dev *dev,
+                               u32 portid, u32 seq,
+                               struct netlink_callback *cb,
+                               int flags)
+{
+       void *hdr;
+       struct nfc_se *se, *n;
+
+       list_for_each_entry_safe(se, n, &dev->secure_elements, list) {
+               hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags,
+                                 NFC_CMD_GET_SE);
+               if (!hdr)
+                       goto nla_put_failure;
+
+               if (cb)
+                       genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
+
+               if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
+                   nla_put_u32(msg, NFC_ATTR_SE_INDEX, se->idx) ||
+                   nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type))
+                       goto nla_put_failure;
+
+               if (genlmsg_end(msg, hdr) < 0)
+                       goto nla_put_failure;
+       }
+
+       return 0;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return -EMSGSIZE;
+}
+
+static int nfc_genl_dump_ses(struct sk_buff *skb,
+                                struct netlink_callback *cb)
+{
+       struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
+       struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
+       bool first_call = false;
+
+       if (!iter) {
+               first_call = true;
+               iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
+               if (!iter)
+                       return -ENOMEM;
+               cb->args[0] = (long) iter;
+       }
+
+       mutex_lock(&nfc_devlist_mutex);
+
+       cb->seq = nfc_devlist_generation;
+
+       if (first_call) {
+               nfc_device_iter_init(iter);
+               dev = nfc_device_iter_next(iter);
+       }
+
+       while (dev) {
+               int rc;
+
+               rc = nfc_genl_send_se(skb, dev, NETLINK_CB(cb->skb).portid,
+                                         cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
+               if (rc < 0)
+                       break;
+
+               dev = nfc_device_iter_next(iter);
+       }
+
+       mutex_unlock(&nfc_devlist_mutex);
+
+       cb->args[1] = (long) dev;
+
+       return skb->len;
+}
+
+static int nfc_genl_dump_ses_done(struct netlink_callback *cb)
+{
+       struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
+
+       nfc_device_iter_exit(iter);
+       kfree(iter);
+
+       return 0;
+}
+
 static struct genl_ops nfc_genl_ops[] = {
        {
                .cmd = NFC_CMD_GET_DEVICE,
@@ -1265,6 +1350,12 @@ static struct genl_ops nfc_genl_ops[] = {
                .doit = nfc_genl_disable_se,
                .policy = nfc_genl_policy,
        },
+       {
+               .cmd = NFC_CMD_GET_SE,
+               .dumpit = nfc_genl_dump_ses,
+               .done = nfc_genl_dump_ses_done,
+               .policy = nfc_genl_policy,
+       },
 };