diff options
author | Thierry Escande <thierry.escande@linux.intel.com> | 2013-02-15 04:43:06 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-03-10 18:14:54 -0400 |
commit | d9b8d8e19b073096d3609bbd60f82148d128b555 (patch) | |
tree | 0888a7ff7367bc5efd1b5e1388bc59aab308451c /net/nfc | |
parent | e0ae7bac06ccb90bb0cf7a3362730b48c7d7f1a8 (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.c | 78 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.c | 32 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.h | 9 | ||||
-rw-r--r-- | net/nfc/netlink.c | 169 | ||||
-rw-r--r-- | net/nfc/nfc.h | 14 |
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 | ||
147 | struct 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 | |||
147 | void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp) | 182 | void 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 | ||
188 | void 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 | |||
153 | int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local, | 200 | int 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 | ||
561 | int 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 | |||
514 | int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason) | 592 | int 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 | ||
1241 | exit: | 1267 | exit: |
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, | |||
230 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); | 234 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); |
231 | u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length); | 235 | u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length); |
232 | struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap); | 236 | struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap); |
237 | struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri, | ||
238 | size_t uri_len); | ||
233 | void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp); | 239 | void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp); |
240 | void nfc_llcp_free_sdp_tlv_list(struct hlist_head *sdp_head); | ||
234 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); | 241 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); |
235 | int nfc_llcp_disconnect(struct nfc_llcp_sock *sock); | 242 | int nfc_llcp_disconnect(struct nfc_llcp_sock *sock); |
236 | int nfc_llcp_send_symm(struct nfc_dev *dev); | 243 | int nfc_llcp_send_symm(struct nfc_dev *dev); |
@@ -238,6 +245,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock); | |||
238 | int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); | 245 | int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); |
239 | int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local, | 246 | int 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); |
248 | int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local, | ||
249 | struct hlist_head *tlv_list, size_t tlvs_len); | ||
241 | int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); | 250 | int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); |
242 | int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); | 251 | int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); |
243 | int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | 252 | int 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 | |||
62 | static 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 | ||
61 | static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, | 67 | static 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 | ||
360 | int 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 | |||
417 | nla_put_failure: | ||
418 | genlmsg_cancel(msg, hdr); | ||
419 | |||
420 | free_msg: | ||
421 | nlmsg_free(msg); | ||
422 | |||
423 | nfc_llcp_free_sdp_tlv_list(sdres_list); | ||
424 | |||
425 | return rc; | ||
426 | } | ||
427 | |||
354 | static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev, | 428 | static 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 | ||
939 | static 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); | ||
1021 | exit: | ||
1022 | device_unlock(&dev->dev); | ||
1023 | |||
1024 | nfc_put_device(dev); | ||
1025 | |||
1026 | return rc; | ||
1027 | } | ||
1028 | |||
865 | static struct genl_ops nfc_genl_ops[] = { | 1029 | static 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 | ||
49 | struct nfc_llcp_sdp_tlv; | ||
50 | |||
49 | #ifdef CONFIG_NFC_LLCP | 51 | #ifdef CONFIG_NFC_LLCP |
50 | 52 | ||
51 | void nfc_llcp_mac_is_down(struct nfc_dev *dev); | 53 | void 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); | |||
59 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); | 61 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); |
60 | int __init nfc_llcp_init(void); | 62 | int __init nfc_llcp_init(void); |
61 | void nfc_llcp_exit(void); | 63 | void nfc_llcp_exit(void); |
64 | void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp); | ||
65 | void 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 | ||
119 | static inline void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp) | ||
120 | { | ||
121 | } | ||
122 | |||
123 | static inline void nfc_llcp_free_sdp_tlv_list(struct hlist_head *sdp_head) | ||
124 | { | ||
125 | } | ||
126 | |||
115 | #endif | 127 | #endif |
116 | 128 | ||
117 | int __init rawsock_init(void); | 129 | int __init rawsock_init(void); |
@@ -144,6 +156,8 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev); | |||
144 | int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol); | 156 | int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol); |
145 | int nfc_genl_tm_deactivated(struct nfc_dev *dev); | 157 | int nfc_genl_tm_deactivated(struct nfc_dev *dev); |
146 | 158 | ||
159 | int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list); | ||
160 | |||
147 | struct nfc_dev *nfc_get_device(unsigned int idx); | 161 | struct nfc_dev *nfc_get_device(unsigned int idx); |
148 | 162 | ||
149 | static inline void nfc_put_device(struct nfc_dev *dev) | 163 | static inline void nfc_put_device(struct nfc_dev *dev) |