|
@@ -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,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
|