Commit e65b0f46edfda746ba8c66ada28ccb97c682b7c0

Authored by Samuel Ortiz
Committed by John W. Linville
1 parent eda21f16a5

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>

Showing 1 changed file with 43 additions and 14 deletions Side-by-side Diff

net/nfc/llcp/commands.c
... ... @@ -444,29 +444,58 @@
444 444 struct msghdr *msg, size_t len)
445 445 {
446 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);
452   - if (pdu == NULL)
  454 + local = sock->local;
  455 + if (local == NULL)
  456 + return -ENODEV;
  457 +
  458 + msg_data = kzalloc(len, GFP_KERNEL);
  459 + if (msg_data == NULL)
453 460 return -ENOMEM;
454 461  
455   - skb_put(pdu, LLCP_SEQUENCE_SIZE);
456   -
457   - if (memcpy_fromiovec(skb_put(pdu, len), msg->msg_iov, len)) {
458   - kfree_skb(pdu);
459   - return -EFAULT;
  462 + if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) {
  463 + kfree(msg_data);
  464 + return -EFAULT;
460 465 }
461 466  
462   - skb_queue_head(&sock->tx_queue, pdu);
  467 + remaining_len = len;
  468 + msg_ptr = msg_data;
463 469  
464   - sk = &sock->sk;
465   - lock_sock(sk);
  470 + while (remaining_len > 0) {
466 471  
467   - nfc_llcp_queue_i_frames(sock);
  472 + frag_len = min_t(u16, local->remote_miu, remaining_len);
468 473  
469   - release_sock(sk);
  474 + pr_debug("Fragment %zd bytes remaining %zd",
  475 + frag_len, remaining_len);
  476 +
  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 + }
  497 +
  498 + kfree(msg_data);
470 499  
471 500 return 0;
472 501 }