Commit e65b0f46 authored by Samuel Ortiz's avatar Samuel Ortiz Committed by John W. Linville
Browse files

NFC: Fragment LLCP I frames



Based on the receiver MIU, we have to fragment the frame to be
transmitted.

Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent eda21f16
Loading
Loading
Loading
Loading
+43 −14
Original line number Original line Diff line number Diff line
@@ -444,30 +444,59 @@ 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 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 len %zd\n", len);

	local = sock->local;
	if (local == NULL)
		return -ENODEV;

	msg_data = kzalloc(len, GFP_KERNEL);
	if (msg_data == NULL)
		return -ENOMEM;


	pr_debug("Send I frame\n");
	if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) {
			kfree(msg_data);
			return -EFAULT;
	}


	pdu = llcp_allocate_pdu(sock, LLCP_PDU_I, len + LLCP_SEQUENCE_SIZE);
	remaining_len = len;
	msg_ptr = msg_data;

	while (remaining_len > 0) {

		frag_len = min_t(u16, local->remote_miu, remaining_len);

		pr_debug("Fragment %zd bytes remaining %zd",
			 frag_len, remaining_len);

		pdu = llcp_allocate_pdu(sock, LLCP_PDU_I,
					frag_len + LLCP_SEQUENCE_SIZE);
		if (pdu == NULL)
		if (pdu == NULL)
			return -ENOMEM;
			return -ENOMEM;


		skb_put(pdu, LLCP_SEQUENCE_SIZE);
		skb_put(pdu, LLCP_SEQUENCE_SIZE);


	if (memcpy_fromiovec(skb_put(pdu, len), msg->msg_iov, len)) {
		memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
		kfree_skb(pdu);
		return -EFAULT;
	}


		skb_queue_head(&sock->tx_queue, pdu);
		skb_queue_head(&sock->tx_queue, pdu);


	sk = &sock->sk;
		lock_sock(sk);
		lock_sock(sk);


		nfc_llcp_queue_i_frames(sock);
		nfc_llcp_queue_i_frames(sock);


		release_sock(sk);
		release_sock(sk);


		remaining_len -= frag_len;
		msg_ptr += len;
	}

	kfree(msg_data);

	return 0;
	return 0;
}
}