From 53a0ac2ee810cf82ec374b686a1dc3c32399265a Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:37 +0100 Subject: NFC: LLCP socket sendmsg implemetation Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'net/nfc/llcp/commands.c') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 151f2ef429c4..f6c2257c11aa 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -397,3 +397,34 @@ int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock) return 0; } + +int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, + struct msghdr *msg, size_t len) +{ + struct sk_buff *pdu; + struct sock *sk; + + pr_debug("Send I frame\n"); + + pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, len + LLCP_SEQUENCE_SIZE); + if (pdu == NULL) + return -ENOMEM; + + skb_put(pdu, LLCP_SEQUENCE_SIZE); + + if (memcpy_fromiovec(skb_put(pdu, len), msg->msg_iov, len)) { + kfree_skb(pdu); + return -EFAULT; + } + + skb_queue_head(&sock->tx_queue, pdu); + + sk = &sock->sk; + lock_sock(sk); + + nfc_llcp_queue_i_frames(sock); + + release_sock(sk); + + return 0; +} -- cgit v1.2.3 From d094afa155273e03b82981ea818d39c7a2dfba86 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:42 +0100 Subject: NFC: Send LLCP RR frames to acknowledge received I frames In order to acknowledge an I frame, we have to either queue pending local I frames or queue a receiver ready frame. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'net/nfc/llcp/commands.c') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index f6c2257c11aa..8ebd322b11eb 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -428,3 +428,27 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, return 0; } + +int nfc_llcp_send_rr(struct nfc_llcp_sock *sock) +{ + struct sk_buff *skb; + struct nfc_llcp_local *local; + + pr_debug("Send rr nr %d\n", sock->recv_n); + + local = sock->local; + if (local == NULL) + return -ENODEV; + + skb = llcp_allocate_pdu(sock, LLCP_PDU_RR, LLCP_SEQUENCE_SIZE); + if (skb == NULL) + return -ENOMEM; + + skb_put(skb, LLCP_SEQUENCE_SIZE); + + skb->data[2] = sock->recv_n % 16; + + skb_queue_head(&local->tx_queue, skb); + + return 0; +} -- cgit v1.2.3 From eda21f16a5ed2476c1740e83a7dfaae34d893d9b Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:43 +0100 Subject: NFC: Set MIU and RW values from CONNECT and CC LLCP frames We use the maximum values for the LLCP Maximum Information Unit and Receive Window Size. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) (limited to 'net/nfc/llcp/commands.c') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 8ebd322b11eb..a02292ba25c7 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -284,6 +284,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) struct nfc_llcp_local *local; struct sk_buff *skb; u8 *service_name_tlv = NULL, service_name_tlv_length; + u8 *miux_tlv = NULL, miux_tlv_length; + u8 *rw_tlv = NULL, rw_tlv_length, rw; + __be16 miux; int err; u16 size = 0; @@ -301,6 +304,14 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) size += service_name_tlv_length; } + miux = cpu_to_be16(LLCP_MAX_MIUX); + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, &miux_tlv_length); + size += miux_tlv_length; + + rw = LLCP_MAX_RW; + rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); + size += rw_tlv_length; + pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len); skb = llcp_allocate_pdu(sock, LLCP_PDU_CONNECT, size); @@ -313,6 +324,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) skb = llcp_add_tlv(skb, service_name_tlv, service_name_tlv_length); + skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length); + skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length); + skb_queue_tail(&local->tx_queue, skb); return 0; @@ -321,6 +335,8 @@ error_tlv: pr_err("error %d\n", err); kfree(service_name_tlv); + kfree(miux_tlv); + kfree(rw_tlv); return err; } @@ -329,6 +345,11 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) { struct nfc_llcp_local *local; struct sk_buff *skb; + u8 *miux_tlv = NULL, miux_tlv_length; + u8 *rw_tlv = NULL, rw_tlv_length, rw; + __be16 miux; + int err; + u16 size = 0; pr_debug("Sending CC\n"); @@ -336,13 +357,34 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) if (local == NULL) return -ENODEV; - skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, 0); - if (skb == NULL) - return -ENOMEM; + miux = cpu_to_be16(LLCP_MAX_MIUX); + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, &miux_tlv_length); + size += miux_tlv_length; + + rw = LLCP_MAX_RW; + rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); + size += rw_tlv_length; + + skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size); + if (skb == NULL) { + err = -ENOMEM; + goto error_tlv; + } + + skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length); + skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length); skb_queue_tail(&local->tx_queue, skb); return 0; + +error_tlv: + pr_err("error %d\n", err); + + kfree(miux_tlv); + kfree(rw_tlv); + + return err; } int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason) -- cgit v1.2.3 From e65b0f46edfda746ba8c66ada28ccb97c682b7c0 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:44 +0100 Subject: NFC: Fragment LLCP I frames Based on the receiver MIU, we have to fragment the frame to be transmitted. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 57 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 14 deletions(-) (limited to 'net/nfc/llcp/commands.c') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index a02292ba25c7..bfe35b8f225e 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -444,29 +444,58 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, struct msghdr *msg, size_t len) { struct sk_buff *pdu; - struct sock *sk; + struct sock *sk = &sock->sk; + struct nfc_llcp_local *local; + size_t frag_len = 0, remaining_len; + u8 *msg_data, *msg_ptr; - pr_debug("Send I frame\n"); + pr_debug("Send I frame len %zd\n", len); - pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, len + LLCP_SEQUENCE_SIZE); - if (pdu == NULL) - return -ENOMEM; + local = sock->local; + if (local == NULL) + return -ENODEV; - skb_put(pdu, LLCP_SEQUENCE_SIZE); + msg_data = kzalloc(len, GFP_KERNEL); + if (msg_data == NULL) + return -ENOMEM; - if (memcpy_fromiovec(skb_put(pdu, len), msg->msg_iov, len)) { - kfree_skb(pdu); - return -EFAULT; + if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) { + kfree(msg_data); + return -EFAULT; } - skb_queue_head(&sock->tx_queue, pdu); + remaining_len = len; + msg_ptr = msg_data; + + while (remaining_len > 0) { + + frag_len = min_t(u16, local->remote_miu, remaining_len); - sk = &sock->sk; - lock_sock(sk); + pr_debug("Fragment %zd bytes remaining %zd", + frag_len, remaining_len); - nfc_llcp_queue_i_frames(sock); + pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, + frag_len + LLCP_SEQUENCE_SIZE); + if (pdu == NULL) + return -ENOMEM; + + skb_put(pdu, LLCP_SEQUENCE_SIZE); + + memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); + + skb_queue_head(&sock->tx_queue, pdu); + + lock_sock(sk); + + nfc_llcp_queue_i_frames(sock); + + release_sock(sk); + + remaining_len -= frag_len; + msg_ptr += len; + } - release_sock(sk); + kfree(msg_data); return 0; } -- cgit v1.2.3 From 9dda50f4c98f84e32a5f6dc4d9dd7af6085add43 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:49 +0100 Subject: NFC: SN is not an invalid GT value We just don't do anything with it when parsing the general bytes. We handle it from the CONNECT reception code. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/nfc/llcp/commands.c') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index bfe35b8f225e..7c74b82f2161 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -152,6 +152,8 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local, case LLCP_TLV_RW: local->remote_rw = llcp_tlv_rw(tlv); break; + case LLCP_TLV_SN: + break; default: pr_err("Invalid gt tlv value 0x%x\n", type); break; -- cgit v1.2.3 From 427a2eb1f568c9c5934a36105232c94553db9b69 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 5 Mar 2012 01:03:52 +0100 Subject: NFC: LLCP code identation fixes Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- net/nfc/llcp/commands.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'net/nfc/llcp/commands.c') diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 7c74b82f2161..7b76eb7192f3 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -118,7 +118,7 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length) } int nfc_llcp_parse_tlv(struct nfc_llcp_local *local, - u8 *tlv_array, u16 tlv_array_len) + u8 *tlv_array, u16 tlv_array_len) { u8 *tlv = tlv_array, type, length, offset = 0; @@ -164,15 +164,15 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local, } pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x rw %d\n", - local->remote_version, local->remote_miu, - local->remote_lto, local->remote_opt, - local->remote_wks, local->remote_rw); + local->remote_version, local->remote_miu, + local->remote_lto, local->remote_opt, + local->remote_wks, local->remote_rw); return 0; } static struct sk_buff *llcp_add_header(struct sk_buff *pdu, - u8 dsap, u8 ssap, u8 ptype) + u8 dsap, u8 ssap, u8 ptype) { u8 header[2]; @@ -188,7 +188,8 @@ static struct sk_buff *llcp_add_header(struct sk_buff *pdu, return pdu; } -static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, u8 tlv_length) +static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, + u8 tlv_length) { /* XXX Add an skb length check */ @@ -201,7 +202,7 @@ static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, u8 tlv_length) } static struct sk_buff *llcp_allocate_pdu(struct nfc_llcp_sock *sock, - u8 cmd, u16 size) + u8 cmd, u16 size) { struct sk_buff *skb; int err; @@ -210,7 +211,7 @@ static struct sk_buff *llcp_allocate_pdu(struct nfc_llcp_sock *sock, return NULL; skb = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT, - size + LLCP_HEADER_SIZE, &err); + size + LLCP_HEADER_SIZE, &err); if (skb == NULL) { pr_err("Could not allocate PDU\n"); return NULL; @@ -278,7 +279,7 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM); return nfc_data_exchange(dev, local->target_idx, skb, - nfc_llcp_recv, local); + nfc_llcp_recv, local); } int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) @@ -300,14 +301,15 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) if (sock->service_name != NULL) { service_name_tlv = nfc_llcp_build_tlv(LLCP_TLV_SN, - sock->service_name, - sock->service_name_len, - &service_name_tlv_length); + sock->service_name, + sock->service_name_len, + &service_name_tlv_length); size += service_name_tlv_length; } miux = cpu_to_be16(LLCP_MAX_MIUX); - miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, &miux_tlv_length); + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, + &miux_tlv_length); size += miux_tlv_length; rw = LLCP_MAX_RW; @@ -324,7 +326,7 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) if (service_name_tlv != NULL) skb = llcp_add_tlv(skb, service_name_tlv, - service_name_tlv_length); + service_name_tlv_length); skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length); skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length); @@ -360,7 +362,8 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) return -ENODEV; miux = cpu_to_be16(LLCP_MAX_MIUX); - miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, &miux_tlv_length); + miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, + &miux_tlv_length); size += miux_tlv_length; rw = LLCP_MAX_RW; @@ -443,7 +446,7 @@ int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock) } int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, - struct msghdr *msg, size_t len) + struct msghdr *msg, size_t len) { struct sk_buff *pdu; struct sock *sk = &sock->sk; @@ -462,8 +465,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, return -ENOMEM; if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) { - kfree(msg_data); - return -EFAULT; + kfree(msg_data); + return -EFAULT; } remaining_len = len; -- cgit v1.2.3