diff options
author | Samuel Ortiz <sameo@linux.intel.com> | 2012-03-04 19:03:44 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-03-06 15:16:22 -0500 |
commit | e65b0f46edfda746ba8c66ada28ccb97c682b7c0 (patch) | |
tree | dbe6f0a78731cf008356f40aa02d4036265f590d /net | |
parent | eda21f16a5ed2476c1740e83a7dfaae34d893d9b (diff) |
NFC: Fragment LLCP I frames
Based on the receiver MIU, we have to fragment the frame to be
transmitted.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/nfc/llcp/commands.c | 57 |
1 files changed, 43 insertions, 14 deletions
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, | |||
444 | struct msghdr *msg, size_t len) | 444 | struct msghdr *msg, size_t len) |
445 | { | 445 | { |
446 | struct sk_buff *pdu; | 446 | struct sk_buff *pdu; |
447 | struct sock *sk; | 447 | struct sock *sk = &sock->sk; |
448 | struct nfc_llcp_local *local; | ||
449 | size_t frag_len = 0, remaining_len; | ||
450 | u8 *msg_data, *msg_ptr; | ||
448 | 451 | ||
449 | pr_debug("Send I frame\n"); | 452 | pr_debug("Send I frame len %zd\n", len); |
450 | 453 | ||
451 | pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, len + LLCP_SEQUENCE_SIZE); | 454 | local = sock->local; |
452 | if (pdu == NULL) | 455 | if (local == NULL) |
453 | return -ENOMEM; | 456 | return -ENODEV; |
454 | 457 | ||
455 | skb_put(pdu, LLCP_SEQUENCE_SIZE); | 458 | msg_data = kzalloc(len, GFP_KERNEL); |
459 | if (msg_data == NULL) | ||
460 | return -ENOMEM; | ||
456 | 461 | ||
457 | if (memcpy_fromiovec(skb_put(pdu, len), msg->msg_iov, len)) { | 462 | if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) { |
458 | kfree_skb(pdu); | 463 | kfree(msg_data); |
459 | return -EFAULT; | 464 | return -EFAULT; |
460 | } | 465 | } |
461 | 466 | ||
462 | skb_queue_head(&sock->tx_queue, pdu); | 467 | remaining_len = len; |
468 | msg_ptr = msg_data; | ||
469 | |||
470 | while (remaining_len > 0) { | ||
471 | |||
472 | frag_len = min_t(u16, local->remote_miu, remaining_len); | ||
463 | 473 | ||
464 | sk = &sock->sk; | 474 | pr_debug("Fragment %zd bytes remaining %zd", |
465 | lock_sock(sk); | 475 | frag_len, remaining_len); |
466 | 476 | ||
467 | nfc_llcp_queue_i_frames(sock); | 477 | pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, |
478 | frag_len + LLCP_SEQUENCE_SIZE); | ||
479 | if (pdu == NULL) | ||
480 | return -ENOMEM; | ||
481 | |||
482 | skb_put(pdu, LLCP_SEQUENCE_SIZE); | ||
483 | |||
484 | memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); | ||
485 | |||
486 | skb_queue_head(&sock->tx_queue, pdu); | ||
487 | |||
488 | lock_sock(sk); | ||
489 | |||
490 | nfc_llcp_queue_i_frames(sock); | ||
491 | |||
492 | release_sock(sk); | ||
493 | |||
494 | remaining_len -= frag_len; | ||
495 | msg_ptr += len; | ||
496 | } | ||
468 | 497 | ||
469 | release_sock(sk); | 498 | kfree(msg_data); |
470 | 499 | ||
471 | return 0; | 500 | return 0; |
472 | } | 501 | } |