diff options
Diffstat (limited to 'net/nfc/netlink.c')
-rw-r--r-- | net/nfc/netlink.c | 175 |
1 files changed, 173 insertions, 2 deletions
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 504b883439f1..f0c4d61f37c0 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c | |||
@@ -28,8 +28,7 @@ | |||
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | 29 | ||
30 | #include "nfc.h" | 30 | #include "nfc.h" |
31 | 31 | #include "llcp.h" | |
32 | #include "llcp/llcp.h" | ||
33 | 32 | ||
34 | static struct genl_multicast_group nfc_genl_event_mcgrp = { | 33 | static struct genl_multicast_group nfc_genl_event_mcgrp = { |
35 | .name = NFC_GENL_MCAST_EVENT_NAME, | 34 | .name = NFC_GENL_MCAST_EVENT_NAME, |
@@ -53,6 +52,15 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = { | |||
53 | [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 }, | 52 | [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 }, |
54 | [NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 }, | 53 | [NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 }, |
55 | [NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 }, | 54 | [NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 }, |
55 | [NFC_ATTR_LLC_PARAM_LTO] = { .type = NLA_U8 }, | ||
56 | [NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 }, | ||
57 | [NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 }, | ||
58 | [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED }, | ||
59 | }; | ||
60 | |||
61 | static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { | ||
62 | [NFC_SDP_ATTR_URI] = { .type = NLA_STRING }, | ||
63 | [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 }, | ||
56 | }; | 64 | }; |
57 | 65 | ||
58 | static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, | 66 | static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, |
@@ -348,6 +356,74 @@ free_msg: | |||
348 | return -EMSGSIZE; | 356 | return -EMSGSIZE; |
349 | } | 357 | } |
350 | 358 | ||
359 | int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list) | ||
360 | { | ||
361 | struct sk_buff *msg; | ||
362 | struct nlattr *sdp_attr, *uri_attr; | ||
363 | struct nfc_llcp_sdp_tlv *sdres; | ||
364 | struct hlist_node *n; | ||
365 | void *hdr; | ||
366 | int rc = -EMSGSIZE; | ||
367 | int i; | ||
368 | |||
369 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
370 | if (!msg) | ||
371 | return -ENOMEM; | ||
372 | |||
373 | hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, | ||
374 | NFC_EVENT_LLC_SDRES); | ||
375 | if (!hdr) | ||
376 | goto free_msg; | ||
377 | |||
378 | if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) | ||
379 | goto nla_put_failure; | ||
380 | |||
381 | sdp_attr = nla_nest_start(msg, NFC_ATTR_LLC_SDP); | ||
382 | if (sdp_attr == NULL) { | ||
383 | rc = -ENOMEM; | ||
384 | goto nla_put_failure; | ||
385 | } | ||
386 | |||
387 | i = 1; | ||
388 | hlist_for_each_entry_safe(sdres, n, sdres_list, node) { | ||
389 | pr_debug("uri: %s, sap: %d\n", sdres->uri, sdres->sap); | ||
390 | |||
391 | uri_attr = nla_nest_start(msg, i++); | ||
392 | if (uri_attr == NULL) { | ||
393 | rc = -ENOMEM; | ||
394 | goto nla_put_failure; | ||
395 | } | ||
396 | |||
397 | if (nla_put_u8(msg, NFC_SDP_ATTR_SAP, sdres->sap)) | ||
398 | goto nla_put_failure; | ||
399 | |||
400 | if (nla_put_string(msg, NFC_SDP_ATTR_URI, sdres->uri)) | ||
401 | goto nla_put_failure; | ||
402 | |||
403 | nla_nest_end(msg, uri_attr); | ||
404 | |||
405 | hlist_del(&sdres->node); | ||
406 | |||
407 | nfc_llcp_free_sdp_tlv(sdres); | ||
408 | } | ||
409 | |||
410 | nla_nest_end(msg, sdp_attr); | ||
411 | |||
412 | genlmsg_end(msg, hdr); | ||
413 | |||
414 | return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); | ||
415 | |||
416 | nla_put_failure: | ||
417 | genlmsg_cancel(msg, hdr); | ||
418 | |||
419 | free_msg: | ||
420 | nlmsg_free(msg); | ||
421 | |||
422 | nfc_llcp_free_sdp_tlv_list(sdres_list); | ||
423 | |||
424 | return rc; | ||
425 | } | ||
426 | |||
351 | static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, | 427 | static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, |
352 | u32 portid, u32 seq, | 428 | u32 portid, u32 seq, |
353 | struct netlink_callback *cb, | 429 | struct netlink_callback *cb, |
@@ -859,6 +935,96 @@ exit: | |||
859 | return rc; | 935 | return rc; |
860 | } | 936 | } |
861 | 937 | ||
938 | static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info) | ||
939 | { | ||
940 | struct nfc_dev *dev; | ||
941 | struct nfc_llcp_local *local; | ||
942 | struct nlattr *attr, *sdp_attrs[NFC_SDP_ATTR_MAX+1]; | ||
943 | u32 idx; | ||
944 | u8 tid; | ||
945 | char *uri; | ||
946 | int rc = 0, rem; | ||
947 | size_t uri_len, tlvs_len; | ||
948 | struct hlist_head sdreq_list; | ||
949 | struct nfc_llcp_sdp_tlv *sdreq; | ||
950 | |||
951 | if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || | ||
952 | !info->attrs[NFC_ATTR_LLC_SDP]) | ||
953 | return -EINVAL; | ||
954 | |||
955 | idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); | ||
956 | |||
957 | dev = nfc_get_device(idx); | ||
958 | if (!dev) { | ||
959 | rc = -ENODEV; | ||
960 | goto exit; | ||
961 | } | ||
962 | |||
963 | device_lock(&dev->dev); | ||
964 | |||
965 | if (dev->dep_link_up == false) { | ||
966 | rc = -ENOLINK; | ||
967 | goto exit; | ||
968 | } | ||
969 | |||
970 | local = nfc_llcp_find_local(dev); | ||
971 | if (!local) { | ||
972 | nfc_put_device(dev); | ||
973 | rc = -ENODEV; | ||
974 | goto exit; | ||
975 | } | ||
976 | |||
977 | INIT_HLIST_HEAD(&sdreq_list); | ||
978 | |||
979 | tlvs_len = 0; | ||
980 | |||
981 | nla_for_each_nested(attr, info->attrs[NFC_ATTR_LLC_SDP], rem) { | ||
982 | rc = nla_parse_nested(sdp_attrs, NFC_SDP_ATTR_MAX, attr, | ||
983 | nfc_sdp_genl_policy); | ||
984 | |||
985 | if (rc != 0) { | ||
986 | rc = -EINVAL; | ||
987 | goto exit; | ||
988 | } | ||
989 | |||
990 | if (!sdp_attrs[NFC_SDP_ATTR_URI]) | ||
991 | continue; | ||
992 | |||
993 | uri_len = nla_len(sdp_attrs[NFC_SDP_ATTR_URI]); | ||
994 | if (uri_len == 0) | ||
995 | continue; | ||
996 | |||
997 | uri = nla_data(sdp_attrs[NFC_SDP_ATTR_URI]); | ||
998 | if (uri == NULL || *uri == 0) | ||
999 | continue; | ||
1000 | |||
1001 | tid = local->sdreq_next_tid++; | ||
1002 | |||
1003 | sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len); | ||
1004 | if (sdreq == NULL) { | ||
1005 | rc = -ENOMEM; | ||
1006 | goto exit; | ||
1007 | } | ||
1008 | |||
1009 | tlvs_len += sdreq->tlv_len; | ||
1010 | |||
1011 | hlist_add_head(&sdreq->node, &sdreq_list); | ||
1012 | } | ||
1013 | |||
1014 | if (hlist_empty(&sdreq_list)) { | ||
1015 | rc = -EINVAL; | ||
1016 | goto exit; | ||
1017 | } | ||
1018 | |||
1019 | rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len); | ||
1020 | exit: | ||
1021 | device_unlock(&dev->dev); | ||
1022 | |||
1023 | nfc_put_device(dev); | ||
1024 | |||
1025 | return rc; | ||
1026 | } | ||
1027 | |||
862 | static struct genl_ops nfc_genl_ops[] = { | 1028 | static struct genl_ops nfc_genl_ops[] = { |
863 | { | 1029 | { |
864 | .cmd = NFC_CMD_GET_DEVICE, | 1030 | .cmd = NFC_CMD_GET_DEVICE, |
@@ -913,6 +1079,11 @@ static struct genl_ops nfc_genl_ops[] = { | |||
913 | .doit = nfc_genl_llc_set_params, | 1079 | .doit = nfc_genl_llc_set_params, |
914 | .policy = nfc_genl_policy, | 1080 | .policy = nfc_genl_policy, |
915 | }, | 1081 | }, |
1082 | { | ||
1083 | .cmd = NFC_CMD_LLC_SDREQ, | ||
1084 | .doit = nfc_genl_llc_sdreq, | ||
1085 | .policy = nfc_genl_policy, | ||
1086 | }, | ||
916 | }; | 1087 | }; |
917 | 1088 | ||
918 | 1089 | ||