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>
This commit is contained in:

committed by
Samuel Ortiz

parent
e0ae7bac06
commit
d9b8d8e19b
@@ -144,12 +144,59 @@ struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap)
|
||||
return sdres;
|
||||
}
|
||||
|
||||
struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
|
||||
size_t uri_len)
|
||||
{
|
||||
struct nfc_llcp_sdp_tlv *sdreq;
|
||||
|
||||
pr_debug("uri: %s, len: %zu\n", uri, uri_len);
|
||||
|
||||
sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
|
||||
if (sdreq == NULL)
|
||||
return NULL;
|
||||
|
||||
sdreq->tlv_len = uri_len + 3;
|
||||
|
||||
if (uri[uri_len - 1] == 0)
|
||||
sdreq->tlv_len--;
|
||||
|
||||
sdreq->tlv = kzalloc(sdreq->tlv_len + 1, GFP_KERNEL);
|
||||
if (sdreq->tlv == NULL) {
|
||||
kfree(sdreq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sdreq->tlv[0] = LLCP_TLV_SDREQ;
|
||||
sdreq->tlv[1] = sdreq->tlv_len - 2;
|
||||
sdreq->tlv[2] = tid;
|
||||
|
||||
sdreq->tid = tid;
|
||||
sdreq->uri = sdreq->tlv + 3;
|
||||
memcpy(sdreq->uri, uri, uri_len);
|
||||
|
||||
INIT_HLIST_NODE(&sdreq->node);
|
||||
|
||||
return sdreq;
|
||||
}
|
||||
|
||||
void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp)
|
||||
{
|
||||
kfree(sdp->tlv);
|
||||
kfree(sdp);
|
||||
}
|
||||
|
||||
void nfc_llcp_free_sdp_tlv_list(struct hlist_head *head)
|
||||
{
|
||||
struct nfc_llcp_sdp_tlv *sdp;
|
||||
struct hlist_node *n;
|
||||
|
||||
hlist_for_each_entry_safe(sdp, n, head, node) {
|
||||
hlist_del(&sdp->node);
|
||||
|
||||
nfc_llcp_free_sdp_tlv(sdp);
|
||||
}
|
||||
}
|
||||
|
||||
int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
|
||||
u8 *tlv_array, u16 tlv_array_len)
|
||||
{
|
||||
@@ -511,6 +558,37 @@ int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local,
|
||||
struct hlist_head *tlv_list, size_t tlvs_len)
|
||||
{
|
||||
struct nfc_llcp_sdp_tlv *sdreq;
|
||||
struct hlist_node *n;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = nfc_llcp_allocate_snl(local, tlvs_len);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
mutex_lock(&local->sdreq_lock);
|
||||
|
||||
hlist_for_each_entry_safe(sdreq, n, tlv_list, node) {
|
||||
pr_debug("tid %d for %s\n", sdreq->tid, sdreq->uri);
|
||||
|
||||
memcpy(skb_put(skb, sdreq->tlv_len), sdreq->tlv,
|
||||
sdreq->tlv_len);
|
||||
|
||||
hlist_del(&sdreq->node);
|
||||
|
||||
hlist_add_head(&sdreq->node, &local->pending_sdreqs);
|
||||
}
|
||||
|
||||
mutex_unlock(&local->sdreq_lock);
|
||||
|
||||
skb_queue_tail(&local->tx_queue, skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
@@ -156,6 +156,7 @@ static void local_release(struct kref *ref)
|
||||
cancel_work_sync(&local->rx_work);
|
||||
cancel_work_sync(&local->timeout_work);
|
||||
kfree_skb(local->rx_pending);
|
||||
nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs);
|
||||
kfree(local);
|
||||
}
|
||||
|
||||
@@ -1147,6 +1148,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
|
||||
struct nfc_llcp_sdp_tlv *sdp;
|
||||
HLIST_HEAD(llc_sdres_list);
|
||||
size_t sdres_tlvs_len;
|
||||
HLIST_HEAD(nl_sdres_list);
|
||||
|
||||
dsap = nfc_llcp_dsap(skb);
|
||||
ssap = nfc_llcp_ssap(skb);
|
||||
@@ -1229,6 +1231,30 @@ add_snl:
|
||||
hlist_add_head(&sdp->node, &llc_sdres_list);
|
||||
break;
|
||||
|
||||
case LLCP_TLV_SDRES:
|
||||
mutex_lock(&local->sdreq_lock);
|
||||
|
||||
pr_debug("LLCP_TLV_SDRES: searching tid %d\n", tlv[2]);
|
||||
|
||||
hlist_for_each_entry(sdp, &local->pending_sdreqs, node) {
|
||||
if (sdp->tid != tlv[2])
|
||||
continue;
|
||||
|
||||
sdp->sap = tlv[3];
|
||||
|
||||
pr_debug("Found: uri=%s, sap=%d\n",
|
||||
sdp->uri, sdp->sap);
|
||||
|
||||
hlist_del(&sdp->node);
|
||||
|
||||
hlist_add_head(&sdp->node, &nl_sdres_list);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&local->sdreq_lock);
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("Invalid SNL tlv value 0x%x\n", type);
|
||||
break;
|
||||
@@ -1239,6 +1265,9 @@ add_snl:
|
||||
}
|
||||
|
||||
exit:
|
||||
if (!hlist_empty(&nl_sdres_list))
|
||||
nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list);
|
||||
|
||||
if (!hlist_empty(&llc_sdres_list))
|
||||
nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
|
||||
}
|
||||
@@ -1426,6 +1455,9 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
|
||||
local->remote_miu = LLCP_DEFAULT_MIU;
|
||||
local->remote_lto = LLCP_DEFAULT_LTO;
|
||||
|
||||
mutex_init(&local->sdreq_lock);
|
||||
INIT_HLIST_HEAD(&local->pending_sdreqs);
|
||||
|
||||
list_add(&local->list, &llcp_devices);
|
||||
|
||||
return 0;
|
||||
|
@@ -97,6 +97,10 @@ struct nfc_llcp_local {
|
||||
u8 remote_opt;
|
||||
u16 remote_wks;
|
||||
|
||||
struct mutex sdreq_lock;
|
||||
struct hlist_head pending_sdreqs;
|
||||
u8 sdreq_next_tid;
|
||||
|
||||
/* sockets array */
|
||||
struct llcp_sock_list sockets;
|
||||
struct llcp_sock_list connecting_sockets;
|
||||
@@ -230,7 +234,10 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
|
||||
void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
|
||||
u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length);
|
||||
struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap);
|
||||
struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
|
||||
size_t uri_len);
|
||||
void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp);
|
||||
void nfc_llcp_free_sdp_tlv_list(struct hlist_head *sdp_head);
|
||||
void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
|
||||
int nfc_llcp_disconnect(struct nfc_llcp_sock *sock);
|
||||
int nfc_llcp_send_symm(struct nfc_dev *dev);
|
||||
@@ -238,6 +245,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
|
||||
int nfc_llcp_send_cc(struct nfc_llcp_sock *sock);
|
||||
int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
|
||||
struct hlist_head *tlv_list, size_t tlvs_len);
|
||||
int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local,
|
||||
struct hlist_head *tlv_list, size_t tlvs_len);
|
||||
int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);
|
||||
int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);
|
||||
int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
|
||||
|
Reference in New Issue
Block a user