aboutsummaryrefslogtreecommitdiffstats
path: root/net/nfc
diff options
context:
space:
mode:
authorThierry Escande <thierry.escande@linux.intel.com>2013-02-15 04:43:06 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2013-03-10 18:14:54 -0400
commitd9b8d8e19b073096d3609bbd60f82148d128b555 (patch)
tree0888a7ff7367bc5efd1b5e1388bc59aab308451c /net/nfc
parente0ae7bac06ccb90bb0cf7a3362730b48c7d7f1a8 (diff)
NFC: llcp: Service Name Lookup netlink interface
This adds a netlink interface for service name lookup support. Multiple URIs can be passed nested into the NFC_ATTR_LLC_SDP attribute using the NFC_CMD_LLC_SDREQ netlink command. When the SNL reply is received, a NFC_EVENT_LLC_SDRES event is sent to the user space. URI and SAP tuples are passed back, nested into NFC_ATTR_LLC_SDP attribute. Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc')
-rw-r--r--net/nfc/llcp/commands.c78
-rw-r--r--net/nfc/llcp/llcp.c32
-rw-r--r--net/nfc/llcp/llcp.h9
-rw-r--r--net/nfc/netlink.c169
-rw-r--r--net/nfc/nfc.h14
5 files changed, 302 insertions, 0 deletions
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c
index 59f7ffca783e..c943edb07b72 100644
--- a/net/nfc/llcp/commands.c
+++ b/net/nfc/llcp/commands.c
@@ -144,12 +144,59 @@ struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap)
144 return sdres; 144 return sdres;
145} 145}
146 146
147struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
148 size_t uri_len)
149{
150 struct nfc_llcp_sdp_tlv *sdreq;
151
152 pr_debug("uri: %s, len: %zu\n", uri, uri_len);
153
154 sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
155 if (sdreq == NULL)
156 return NULL;
157
158 sdreq->tlv_len = uri_len + 3;
159
160 if (uri[uri_len - 1] == 0)
161 sdreq->tlv_len--;
162
163 sdreq->tlv = kzalloc(sdreq->tlv_len + 1, GFP_KERNEL);
164 if (sdreq->tlv == NULL) {
165 kfree(sdreq);
166 return NULL;
167 }
168
169 sdreq->tlv[0] = LLCP_TLV_SDREQ;
170 sdreq->tlv[1] = sdreq->tlv_len - 2;
171 sdreq->tlv[2] = tid;
172
173 sdreq->tid = tid;
174 sdreq->uri = sdreq->tlv + 3;
175 memcpy(sdreq->uri, uri, uri_len);
176
177 INIT_HLIST_NODE(&sdreq->node);
178
179 return sdreq;
180}
181
147void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp) 182void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp)
148{ 183{
149 kfree(sdp->tlv); 184 kfree(sdp->tlv);
150 kfree(sdp); 185 kfree(sdp);
151} 186}
152 187
188void nfc_llcp_free_sdp_tlv_list(struct hlist_head *head)
189{
190 struct nfc_llcp_sdp_tlv *sdp;
191 struct hlist_node *n;
192
193 hlist_for_each_entry_safe(sdp, n, head, node) {
194 hlist_del(&sdp->node);
195
196 nfc_llcp_free_sdp_tlv(sdp);
197 }
198}
199
153int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local, 200int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
154 u8 *tlv_array, u16 tlv_array_len) 201 u8 *tlv_array, u16 tlv_array_len)
155{ 202{
@@ -511,6 +558,37 @@ int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
511 return 0; 558 return 0;
512} 559}
513 560
561int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local,
562 struct hlist_head *tlv_list, size_t tlvs_len)
563{
564 struct nfc_llcp_sdp_tlv *sdreq;
565 struct hlist_node *n;
566 struct sk_buff *skb;
567
568 skb = nfc_llcp_allocate_snl(local, tlvs_len);
569 if (IS_ERR(skb))
570 return PTR_ERR(skb);
571
572 mutex_lock(&local->sdreq_lock);
573
574 hlist_for_each_entry_safe(sdreq, n, tlv_list, node) {
575 pr_debug("tid %d for %s\n", sdreq->tid, sdreq->uri);
576
577 memcpy(skb_put(skb, sdreq->tlv_len), sdreq->tlv,
578 sdreq->tlv_len);
579
580 hlist_del(&sdreq->node);
581
582 hlist_add_head(&sdreq->node, &local->pending_sdreqs);
583 }
584
585 mutex_unlock(&local->sdreq_lock);
586
587 skb_queue_tail(&local->tx_queue, skb);
588
589 return 0;
590}
591
514int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason) 592int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)
515{ 593{
516 struct sk_buff *skb; 594 struct sk_buff *skb;
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 30b61c1aa984..99e911060422 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -156,6 +156,7 @@ static void local_release(struct kref *ref)
156 cancel_work_sync(&local->rx_work); 156 cancel_work_sync(&local->rx_work);
157 cancel_work_sync(&local->timeout_work); 157 cancel_work_sync(&local->timeout_work);
158 kfree_skb(local->rx_pending); 158 kfree_skb(local->rx_pending);
159 nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs);
159 kfree(local); 160 kfree(local);
160} 161}
161 162
@@ -1147,6 +1148,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
1147 struct nfc_llcp_sdp_tlv *sdp; 1148 struct nfc_llcp_sdp_tlv *sdp;
1148 HLIST_HEAD(llc_sdres_list); 1149 HLIST_HEAD(llc_sdres_list);
1149 size_t sdres_tlvs_len; 1150 size_t sdres_tlvs_len;
1151 HLIST_HEAD(nl_sdres_list);
1150 1152
1151 dsap = nfc_llcp_dsap(skb); 1153 dsap = nfc_llcp_dsap(skb);
1152 ssap = nfc_llcp_ssap(skb); 1154 ssap = nfc_llcp_ssap(skb);
@@ -1229,6 +1231,30 @@ add_snl:
1229 hlist_add_head(&sdp->node, &llc_sdres_list); 1231 hlist_add_head(&sdp->node, &llc_sdres_list);
1230 break; 1232 break;
1231 1233
1234 case LLCP_TLV_SDRES:
1235 mutex_lock(&local->sdreq_lock);
1236
1237 pr_debug("LLCP_TLV_SDRES: searching tid %d\n", tlv[2]);
1238
1239 hlist_for_each_entry(sdp, &local->pending_sdreqs, node) {
1240 if (sdp->tid != tlv[2])
1241 continue;
1242
1243 sdp->sap = tlv[3];
1244
1245 pr_debug("Found: uri=%s, sap=%d\n",
1246 sdp->uri, sdp->sap);
1247
1248 hlist_del(&sdp->node);
1249
1250 hlist_add_head(&sdp->node, &nl_sdres_list);
1251
1252 break;
1253 }
1254
1255 mutex_unlock(&local->sdreq_lock);
1256 break;
1257
1232 default: 1258 default:
1233 pr_err("Invalid SNL tlv value 0x%x\n", type); 1259 pr_err("Invalid SNL tlv value 0x%x\n", type);
1234 break; 1260 break;
@@ -1239,6 +1265,9 @@ add_snl:
1239 } 1265 }
1240 1266
1241exit: 1267exit:
1268 if (!hlist_empty(&nl_sdres_list))
1269 nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list);
1270
1242 if (!hlist_empty(&llc_sdres_list)) 1271 if (!hlist_empty(&llc_sdres_list))
1243 nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len); 1272 nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
1244} 1273}
@@ -1426,6 +1455,9 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
1426 local->remote_miu = LLCP_DEFAULT_MIU; 1455 local->remote_miu = LLCP_DEFAULT_MIU;
1427 local->remote_lto = LLCP_DEFAULT_LTO; 1456 local->remote_lto = LLCP_DEFAULT_LTO;
1428 1457
1458 mutex_init(&local->sdreq_lock);
1459 INIT_HLIST_HEAD(&local->pending_sdreqs);
1460
1429 list_add(&local->list, &llcp_devices); 1461 list_add(&local->list, &llcp_devices);
1430 1462
1431 return 0; 1463 return 0;
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h
index 465f5953e2d1..ca8c6d94ab85 100644
--- a/net/nfc/llcp/llcp.h
+++ b/net/nfc/llcp/llcp.h
@@ -97,6 +97,10 @@ struct nfc_llcp_local {
97 u8 remote_opt; 97 u8 remote_opt;
98 u16 remote_wks; 98 u16 remote_wks;
99 99
100 struct mutex sdreq_lock;
101 struct hlist_head pending_sdreqs;
102 u8 sdreq_next_tid;
103
100 /* sockets array */ 104 /* sockets array */
101 struct llcp_sock_list sockets; 105 struct llcp_sock_list sockets;
102 struct llcp_sock_list connecting_sockets; 106 struct llcp_sock_list connecting_sockets;
@@ -230,7 +234,10 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
230void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); 234void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
231u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length); 235u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length);
232struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap); 236struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap);
237struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
238 size_t uri_len);
233void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp); 239void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp);
240void nfc_llcp_free_sdp_tlv_list(struct hlist_head *sdp_head);
234void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); 241void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
235int nfc_llcp_disconnect(struct nfc_llcp_sock *sock); 242int nfc_llcp_disconnect(struct nfc_llcp_sock *sock);
236int nfc_llcp_send_symm(struct nfc_dev *dev); 243int nfc_llcp_send_symm(struct nfc_dev *dev);
@@ -238,6 +245,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
238int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); 245int nfc_llcp_send_cc(struct nfc_llcp_sock *sock);
239int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local, 246int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
240 struct hlist_head *tlv_list, size_t tlvs_len); 247 struct hlist_head *tlv_list, size_t tlvs_len);
248int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local,
249 struct hlist_head *tlv_list, size_t tlvs_len);
241int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); 250int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);
242int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); 251int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);
243int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, 252int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 63975c039b85..73fd51098f4d 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -56,6 +56,12 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
56 [NFC_ATTR_LLC_PARAM_LTO] = { .type = NLA_U8 }, 56 [NFC_ATTR_LLC_PARAM_LTO] = { .type = NLA_U8 },
57 [NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 }, 57 [NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 },
58 [NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 }, 58 [NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 },
59 [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED },
60};
61
62static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = {
63 [NFC_SDP_ATTR_URI] = { .type = NLA_STRING },
64 [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 },
59}; 65};
60 66
61static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, 67static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
@@ -351,6 +357,74 @@ free_msg:
351 return -EMSGSIZE; 357 return -EMSGSIZE;
352} 358}
353 359
360int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list)
361{
362 struct sk_buff *msg;
363 struct nlattr *sdp_attr, *uri_attr;
364 struct nfc_llcp_sdp_tlv *sdres;
365 struct hlist_node *n;
366 void *hdr;
367 int rc = -EMSGSIZE;
368 int i;
369
370 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
371 if (!msg)
372 return -ENOMEM;
373
374 hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
375 NFC_EVENT_LLC_SDRES);
376 if (!hdr)
377 goto free_msg;
378
379 if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
380 goto nla_put_failure;
381
382 sdp_attr = nla_nest_start(msg, NFC_ATTR_LLC_SDP);
383 if (sdp_attr == NULL) {
384 rc = -ENOMEM;
385 goto nla_put_failure;
386 }
387
388 i = 1;
389 hlist_for_each_entry_safe(sdres, n, sdres_list, node) {
390 pr_debug("uri: %s, sap: %d\n", sdres->uri, sdres->sap);
391
392 uri_attr = nla_nest_start(msg, i++);
393 if (uri_attr == NULL) {
394 rc = -ENOMEM;
395 goto nla_put_failure;
396 }
397
398 if (nla_put_u8(msg, NFC_SDP_ATTR_SAP, sdres->sap))
399 goto nla_put_failure;
400
401 if (nla_put_string(msg, NFC_SDP_ATTR_URI, sdres->uri))
402 goto nla_put_failure;
403
404 nla_nest_end(msg, uri_attr);
405
406 hlist_del(&sdres->node);
407
408 nfc_llcp_free_sdp_tlv(sdres);
409 }
410
411 nla_nest_end(msg, sdp_attr);
412
413 genlmsg_end(msg, hdr);
414
415 return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
416
417nla_put_failure:
418 genlmsg_cancel(msg, hdr);
419
420free_msg:
421 nlmsg_free(msg);
422
423 nfc_llcp_free_sdp_tlv_list(sdres_list);
424
425 return rc;
426}
427
354static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, 428static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
355 u32 portid, u32 seq, 429 u32 portid, u32 seq,
356 struct netlink_callback *cb, 430 struct netlink_callback *cb,
@@ -862,6 +936,96 @@ exit:
862 return rc; 936 return rc;
863} 937}
864 938
939static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
940{
941 struct nfc_dev *dev;
942 struct nfc_llcp_local *local;
943 struct nlattr *attr, *sdp_attrs[NFC_SDP_ATTR_MAX+1];
944 u32 idx;
945 u8 tid;
946 char *uri;
947 int rc = 0, rem;
948 size_t uri_len, tlvs_len;
949 struct hlist_head sdreq_list;
950 struct nfc_llcp_sdp_tlv *sdreq;
951
952 if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
953 !info->attrs[NFC_ATTR_LLC_SDP])
954 return -EINVAL;
955
956 idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
957
958 dev = nfc_get_device(idx);
959 if (!dev) {
960 rc = -ENODEV;
961 goto exit;
962 }
963
964 device_lock(&dev->dev);
965
966 if (dev->dep_link_up == false) {
967 rc = -ENOLINK;
968 goto exit;
969 }
970
971 local = nfc_llcp_find_local(dev);
972 if (!local) {
973 nfc_put_device(dev);
974 rc = -ENODEV;
975 goto exit;
976 }
977
978 INIT_HLIST_HEAD(&sdreq_list);
979
980 tlvs_len = 0;
981
982 nla_for_each_nested(attr, info->attrs[NFC_ATTR_LLC_SDP], rem) {
983 rc = nla_parse_nested(sdp_attrs, NFC_SDP_ATTR_MAX, attr,
984 nfc_sdp_genl_policy);
985
986 if (rc != 0) {
987 rc = -EINVAL;
988 goto exit;
989 }
990
991 if (!sdp_attrs[NFC_SDP_ATTR_URI])
992 continue;
993
994 uri_len = nla_len(sdp_attrs[NFC_SDP_ATTR_URI]);
995 if (uri_len == 0)
996 continue;
997
998 uri = nla_data(sdp_attrs[NFC_SDP_ATTR_URI]);
999 if (uri == NULL || *uri == 0)
1000 continue;
1001
1002 tid = local->sdreq_next_tid++;
1003
1004 sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len);
1005 if (sdreq == NULL) {
1006 rc = -ENOMEM;
1007 goto exit;
1008 }
1009
1010 tlvs_len += sdreq->tlv_len;
1011
1012 hlist_add_head(&sdreq->node, &sdreq_list);
1013 }
1014
1015 if (hlist_empty(&sdreq_list)) {
1016 rc = -EINVAL;
1017 goto exit;
1018 }
1019
1020 rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len);
1021exit:
1022 device_unlock(&dev->dev);
1023
1024 nfc_put_device(dev);
1025
1026 return rc;
1027}
1028
865static struct genl_ops nfc_genl_ops[] = { 1029static struct genl_ops nfc_genl_ops[] = {
866 { 1030 {
867 .cmd = NFC_CMD_GET_DEVICE, 1031 .cmd = NFC_CMD_GET_DEVICE,
@@ -916,6 +1080,11 @@ static struct genl_ops nfc_genl_ops[] = {
916 .doit = nfc_genl_llc_set_params, 1080 .doit = nfc_genl_llc_set_params,
917 .policy = nfc_genl_policy, 1081 .policy = nfc_genl_policy,
918 }, 1082 },
1083 {
1084 .cmd = NFC_CMD_LLC_SDREQ,
1085 .doit = nfc_genl_llc_sdreq,
1086 .policy = nfc_genl_policy,
1087 },
919}; 1088};
920 1089
921 1090
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index 87d914d2876a..94bfe19ba678 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -46,6 +46,8 @@ struct nfc_rawsock {
46#define to_rawsock_sk(_tx_work) \ 46#define to_rawsock_sk(_tx_work) \
47 ((struct sock *) container_of(_tx_work, struct nfc_rawsock, tx_work)) 47 ((struct sock *) container_of(_tx_work, struct nfc_rawsock, tx_work))
48 48
49struct nfc_llcp_sdp_tlv;
50
49#ifdef CONFIG_NFC_LLCP 51#ifdef CONFIG_NFC_LLCP
50 52
51void nfc_llcp_mac_is_down(struct nfc_dev *dev); 53void nfc_llcp_mac_is_down(struct nfc_dev *dev);
@@ -59,6 +61,8 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb);
59struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); 61struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
60int __init nfc_llcp_init(void); 62int __init nfc_llcp_init(void);
61void nfc_llcp_exit(void); 63void nfc_llcp_exit(void);
64void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp);
65void nfc_llcp_free_sdp_tlv_list(struct hlist_head *head);
62 66
63#else 67#else
64 68
@@ -112,6 +116,14 @@ static inline void nfc_llcp_exit(void)
112{ 116{
113} 117}
114 118
119static inline void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp)
120{
121}
122
123static inline void nfc_llcp_free_sdp_tlv_list(struct hlist_head *sdp_head)
124{
125}
126
115#endif 127#endif
116 128
117int __init rawsock_init(void); 129int __init rawsock_init(void);
@@ -144,6 +156,8 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev);
144int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol); 156int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol);
145int nfc_genl_tm_deactivated(struct nfc_dev *dev); 157int nfc_genl_tm_deactivated(struct nfc_dev *dev);
146 158
159int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list);
160
147struct nfc_dev *nfc_get_device(unsigned int idx); 161struct nfc_dev *nfc_get_device(unsigned int idx);
148 162
149static inline void nfc_put_device(struct nfc_dev *dev) 163static inline void nfc_put_device(struct nfc_dev *dev)