diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2013-08-27 18:47:24 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-09-24 20:35:05 -0400 |
commit | 5ce3f32b5264b337bfd13a780452a17705307725 (patch) | |
tree | 18dd3052e8d658c5e5682c695056890a382c564d /net/nfc | |
parent | 72b70b6ec4fa7da86a3ac0aacee699b18d94fc3b (diff) |
NFC: netlink: SE API implementation
Implementation of the NFC_CMD_SE_IO command for sending ISO7816 APDUs to
NFC embedded secure elements. The reply is forwarded to user space
through NFC_CMD_SE_IO as well.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/netlink.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 68063b2025da..a3dee05cb64b 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -58,6 +58,7 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { | |||
58 | [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED }, | 58 | [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED }, |
59 | [NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING, | 59 | [NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING, |
60 | .len = NFC_FIRMWARE_NAME_MAXSIZE }, | 60 | .len = NFC_FIRMWARE_NAME_MAXSIZE }, |
61 | [NFC_ATTR_SE_APDU] = { .type = NLA_BINARY }, | ||
61 | }; | 62 | }; |
62 | 63 | ||
63 | static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { | 64 | static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { |
@@ -1278,6 +1279,91 @@ static int nfc_genl_dump_ses_done(struct netlink_callback *cb) | |||
1278 | return 0; | 1279 | return 0; |
1279 | } | 1280 | } |
1280 | 1281 | ||
1282 | struct se_io_ctx { | ||
1283 | u32 dev_idx; | ||
1284 | u32 se_idx; | ||
1285 | }; | ||
1286 | |||
1287 | void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err) | ||
1288 | { | ||
1289 | struct se_io_ctx *ctx = context; | ||
1290 | struct sk_buff *msg; | ||
1291 | void *hdr; | ||
1292 | |||
1293 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1294 | if (!msg) { | ||
1295 | kfree(ctx); | ||
1296 | return; | ||
1297 | } | ||
1298 | |||
1299 | hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, | ||
1300 | NFC_CMD_SE_IO); | ||
1301 | if (!hdr) | ||
1302 | goto free_msg; | ||
1303 | |||
1304 | if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, ctx->dev_idx) || | ||
1305 | nla_put_u32(msg, NFC_ATTR_SE_INDEX, ctx->se_idx) || | ||
1306 | nla_put(msg, NFC_ATTR_SE_APDU, apdu_len, apdu)) | ||
1307 | goto nla_put_failure; | ||
1308 | |||
1309 | genlmsg_end(msg, hdr); | ||
1310 | |||
1311 | genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); | ||
1312 | |||
1313 | kfree(ctx); | ||
1314 | |||
1315 | return; | ||
1316 | |||
1317 | nla_put_failure: | ||
1318 | genlmsg_cancel(msg, hdr); | ||
1319 | free_msg: | ||
1320 | nlmsg_free(msg); | ||
1321 | kfree(ctx); | ||
1322 | |||
1323 | return; | ||
1324 | } | ||
1325 | |||
1326 | static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info) | ||
1327 | { | ||
1328 | struct nfc_dev *dev; | ||
1329 | struct se_io_ctx *ctx; | ||
1330 | u32 dev_idx, se_idx; | ||
1331 | u8 *apdu; | ||
1332 | size_t apdu_len; | ||
1333 | |||
1334 | if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || | ||
1335 | !info->attrs[NFC_ATTR_SE_INDEX] || | ||
1336 | !info->attrs[NFC_ATTR_SE_APDU]) | ||
1337 | return -EINVAL; | ||
1338 | |||
1339 | dev_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); | ||
1340 | se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]); | ||
1341 | |||
1342 | dev = nfc_get_device(dev_idx); | ||
1343 | if (!dev) | ||
1344 | return -ENODEV; | ||
1345 | |||
1346 | if (!dev->ops || !dev->ops->se_io) | ||
1347 | return -ENOTSUPP; | ||
1348 | |||
1349 | apdu_len = nla_len(info->attrs[NFC_ATTR_SE_APDU]); | ||
1350 | if (apdu_len == 0) | ||
1351 | return -EINVAL; | ||
1352 | |||
1353 | apdu = nla_data(info->attrs[NFC_ATTR_SE_APDU]); | ||
1354 | if (!apdu) | ||
1355 | return -EINVAL; | ||
1356 | |||
1357 | ctx = kzalloc(sizeof(struct se_io_ctx), GFP_KERNEL); | ||
1358 | if (!ctx) | ||
1359 | return -ENOMEM; | ||
1360 | |||
1361 | ctx->dev_idx = dev_idx; | ||
1362 | ctx->se_idx = se_idx; | ||
1363 | |||
1364 | return dev->ops->se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx); | ||
1365 | } | ||
1366 | |||
1281 | static struct genl_ops nfc_genl_ops[] = { | 1367 | static struct genl_ops nfc_genl_ops[] = { |
1282 | { | 1368 | { |
1283 | .cmd = NFC_CMD_GET_DEVICE, | 1369 | .cmd = NFC_CMD_GET_DEVICE, |
@@ -1358,6 +1444,11 @@ static struct genl_ops nfc_genl_ops[] = { | |||
1358 | .done = nfc_genl_dump_ses_done, | 1444 | .done = nfc_genl_dump_ses_done, |
1359 | .policy = nfc_genl_policy, | 1445 | .policy = nfc_genl_policy, |
1360 | }, | 1446 | }, |
1447 | { | ||
1448 | .cmd = NFC_CMD_SE_IO, | ||
1449 | .doit = nfc_genl_se_io, | ||
1450 | .policy = nfc_genl_policy, | ||
1451 | }, | ||
1361 | }; | 1452 | }; |
1362 | 1453 | ||
1363 | 1454 | ||