diff options
| -rw-r--r-- | include/uapi/linux/nfc.h | 2 | ||||
| -rw-r--r-- | net/nfc/netlink.c | 91 |
2 files changed, 93 insertions, 0 deletions
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h index 539d60494c04..029921b067fd 100644 --- a/include/uapi/linux/nfc.h +++ b/include/uapi/linux/nfc.h | |||
| @@ -84,6 +84,7 @@ | |||
| 84 | * @NFC_EVENT_SE_TRANSACTION: This event is sent when an application running on | 84 | * @NFC_EVENT_SE_TRANSACTION: This event is sent when an application running on |
| 85 | * a specific SE notifies us about the end of a transaction. The parameter | 85 | * a specific SE notifies us about the end of a transaction. The parameter |
| 86 | * for this event is the application ID (AID). | 86 | * for this event is the application ID (AID). |
| 87 | * @NFC_CMD_GET_SE: Dump all discovered secure elements from an NFC controller. | ||
| 87 | */ | 88 | */ |
| 88 | enum nfc_commands { | 89 | enum nfc_commands { |
| 89 | NFC_CMD_UNSPEC, | 90 | NFC_CMD_UNSPEC, |
| @@ -112,6 +113,7 @@ enum nfc_commands { | |||
| 112 | NFC_EVENT_SE_REMOVED, | 113 | NFC_EVENT_SE_REMOVED, |
| 113 | NFC_EVENT_SE_CONNECTIVITY, | 114 | NFC_EVENT_SE_CONNECTIVITY, |
| 114 | NFC_EVENT_SE_TRANSACTION, | 115 | NFC_EVENT_SE_TRANSACTION, |
| 116 | NFC_CMD_GET_SE, | ||
| 115 | /* private: internal use only */ | 117 | /* private: internal use only */ |
| 116 | __NFC_CMD_AFTER_LAST | 118 | __NFC_CMD_AFTER_LAST |
| 117 | }; | 119 | }; |
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index f16fd59d4160..3b08ef90e045 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
| @@ -1191,6 +1191,91 @@ static int nfc_genl_disable_se(struct sk_buff *skb, struct genl_info *info) | |||
| 1191 | return rc; | 1191 | return rc; |
| 1192 | } | 1192 | } |
| 1193 | 1193 | ||
| 1194 | static int nfc_genl_send_se(struct sk_buff *msg, struct nfc_dev *dev, | ||
| 1195 | u32 portid, u32 seq, | ||
| 1196 | struct netlink_callback *cb, | ||
| 1197 | int flags) | ||
| 1198 | { | ||
| 1199 | void *hdr; | ||
| 1200 | struct nfc_se *se, *n; | ||
| 1201 | |||
| 1202 | list_for_each_entry_safe(se, n, &dev->secure_elements, list) { | ||
| 1203 | hdr = genlmsg_put(msg, portid, seq, &nfc_genl_family, flags, | ||
| 1204 | NFC_CMD_GET_SE); | ||
| 1205 | if (!hdr) | ||
| 1206 | goto nla_put_failure; | ||
| 1207 | |||
| 1208 | if (cb) | ||
| 1209 | genl_dump_check_consistent(cb, hdr, &nfc_genl_family); | ||
| 1210 | |||
| 1211 | if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || | ||
| 1212 | nla_put_u32(msg, NFC_ATTR_SE_INDEX, se->idx) || | ||
| 1213 | nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type)) | ||
| 1214 | goto nla_put_failure; | ||
| 1215 | |||
| 1216 | if (genlmsg_end(msg, hdr) < 0) | ||
| 1217 | goto nla_put_failure; | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | return 0; | ||
| 1221 | |||
| 1222 | nla_put_failure: | ||
| 1223 | genlmsg_cancel(msg, hdr); | ||
| 1224 | return -EMSGSIZE; | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | static int nfc_genl_dump_ses(struct sk_buff *skb, | ||
| 1228 | struct netlink_callback *cb) | ||
| 1229 | { | ||
| 1230 | struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0]; | ||
| 1231 | struct nfc_dev *dev = (struct nfc_dev *) cb->args[1]; | ||
| 1232 | bool first_call = false; | ||
| 1233 | |||
| 1234 | if (!iter) { | ||
| 1235 | first_call = true; | ||
| 1236 | iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL); | ||
| 1237 | if (!iter) | ||
| 1238 | return -ENOMEM; | ||
| 1239 | cb->args[0] = (long) iter; | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | mutex_lock(&nfc_devlist_mutex); | ||
| 1243 | |||
| 1244 | cb->seq = nfc_devlist_generation; | ||
| 1245 | |||
| 1246 | if (first_call) { | ||
| 1247 | nfc_device_iter_init(iter); | ||
| 1248 | dev = nfc_device_iter_next(iter); | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | while (dev) { | ||
| 1252 | int rc; | ||
| 1253 | |||
| 1254 | rc = nfc_genl_send_se(skb, dev, NETLINK_CB(cb->skb).portid, | ||
| 1255 | cb->nlh->nlmsg_seq, cb, NLM_F_MULTI); | ||
| 1256 | if (rc < 0) | ||
| 1257 | break; | ||
| 1258 | |||
| 1259 | dev = nfc_device_iter_next(iter); | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | mutex_unlock(&nfc_devlist_mutex); | ||
| 1263 | |||
| 1264 | cb->args[1] = (long) dev; | ||
| 1265 | |||
| 1266 | return skb->len; | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | static int nfc_genl_dump_ses_done(struct netlink_callback *cb) | ||
| 1270 | { | ||
| 1271 | struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0]; | ||
| 1272 | |||
| 1273 | nfc_device_iter_exit(iter); | ||
| 1274 | kfree(iter); | ||
| 1275 | |||
| 1276 | return 0; | ||
| 1277 | } | ||
| 1278 | |||
| 1194 | static struct genl_ops nfc_genl_ops[] = { | 1279 | static struct genl_ops nfc_genl_ops[] = { |
| 1195 | { | 1280 | { |
| 1196 | .cmd = NFC_CMD_GET_DEVICE, | 1281 | .cmd = NFC_CMD_GET_DEVICE, |
| @@ -1265,6 +1350,12 @@ static struct genl_ops nfc_genl_ops[] = { | |||
| 1265 | .doit = nfc_genl_disable_se, | 1350 | .doit = nfc_genl_disable_se, |
| 1266 | .policy = nfc_genl_policy, | 1351 | .policy = nfc_genl_policy, |
| 1267 | }, | 1352 | }, |
| 1353 | { | ||
| 1354 | .cmd = NFC_CMD_GET_SE, | ||
| 1355 | .dumpit = nfc_genl_dump_ses, | ||
| 1356 | .done = nfc_genl_dump_ses_done, | ||
| 1357 | .policy = nfc_genl_policy, | ||
| 1358 | }, | ||
| 1268 | }; | 1359 | }; |
| 1269 | 1360 | ||
| 1270 | 1361 | ||
