void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
			   int mtyp, struct sk_buff_head *xmitq)
{
	struct sk_buff_head *fdefq = &tnl->failover_deferdq;
	struct sk_buff *skb, *tnlskb;
	struct tipc_msg *hdr, tnlhdr;
	struct sk_buff_head *queue = &l->transmq;
	struct sk_buff_head tmpxq, tnlq, frags;
	u16 pktlen, pktcnt, seqno = l->snd_nxt;
	bool pktcnt_need_update = false;
	u16 syncpt;
	int rc;

	if (!tnl)
		return;

	__skb_queue_head_init(&tnlq);
	/* Link Synching:
	 * From now on, send only one single ("dummy") SYNCH message
	 * to peer. The SYNCH message does not contain any data, just
	 * a header conveying the synch point to the peer.
	 */
	if (mtyp == SYNCH_MSG && (tnl->peer_caps & TIPC_TUNNEL_ENHANCED)) {
		tnlskb = tipc_msg_create(TUNNEL_PROTOCOL, SYNCH_MSG,
					 INT_H_SIZE, 0, l->addr,
					 tipc_own_addr(l->net),
					 0, 0, 0);
		if (!tnlskb) {
			pr_warn("%sunable to create dummy SYNCH_MSG\n",
				link_co_err);
			return;
		}

		hdr = buf_msg(tnlskb);
		syncpt = l->snd_nxt + skb_queue_len(&l->backlogq) - 1;
		msg_set_syncpt(hdr, syncpt);
		msg_set_bearer_id(hdr, l->peer_bearer_id);
		__skb_queue_tail(&tnlq, tnlskb);
		tipc_link_xmit(tnl, &tnlq, xmitq);
		return;
	}

	__skb_queue_head_init(&tmpxq);
	__skb_queue_head_init(&frags);
	/* At least one packet required for safe algorithm => add dummy */
	skb = tipc_msg_create(TIPC_LOW_IMPORTANCE, TIPC_DIRECT_MSG,
			      BASIC_H_SIZE, 0, l->addr, tipc_own_addr(l->net),
			      0, 0, TIPC_ERR_NO_PORT);
	if (!skb) {
		pr_warn("%sunable to create tunnel packet\n", link_co_err);
		return;
	}
	__skb_queue_tail(&tnlq, skb);
	tipc_link_xmit(l, &tnlq, &tmpxq);
	__skb_queue_purge(&tmpxq);

	/* Initialize reusable tunnel packet header */
	tipc_msg_init(tipc_own_addr(l->net), &tnlhdr, TUNNEL_PROTOCOL,
		      mtyp, INT_H_SIZE, l->addr);
	if (mtyp == SYNCH_MSG)
		pktcnt = l->snd_nxt - buf_seqno(skb_peek(&l->transmq));
	else
		pktcnt = skb_queue_len(&l->transmq);
	pktcnt += skb_queue_len(&l->backlogq);
	msg_set_msgcnt(&tnlhdr, pktcnt);
	msg_set_bearer_id(&tnlhdr, l->peer_bearer_id);
tnl:
	/* Wrap each packet into a tunnel packet */
	skb_queue_walk(queue, skb) {
		hdr = buf_msg(skb);
		if (queue == &l->backlogq)
			msg_set_seqno(hdr, seqno++);
		pktlen = msg_size(hdr);

		/* Tunnel link MTU is not large enough? This could be
		 * due to:
		 * 1) Link MTU has just changed or set differently;
		 * 2) Or FAILOVER on the top of a SYNCH message
		 *
		 * The 2nd case should not happen if peer supports
		 * TIPC_TUNNEL_ENHANCED
		 */
		if (pktlen > tnl->mtu - INT_H_SIZE) {
			if (mtyp == FAILOVER_MSG &&
			    (tnl->peer_caps & TIPC_TUNNEL_ENHANCED)) {
				rc = tipc_msg_fragment(skb, &tnlhdr, tnl->mtu,
						       &frags);
				if (rc) {
					pr_warn("%sunable to frag msg: rc %d\n",
						link_co_err, rc);
					return;
				}
				pktcnt += skb_queue_len(&frags) - 1;
				pktcnt_need_update = true;
				skb_queue_splice_tail_init(&frags, &tnlq);
				continue;
			}
			/* Unluckily, peer doesn't have TIPC_TUNNEL_ENHANCED
			 * => Just warn it and return!
			 */
			pr_warn_ratelimited("%stoo large msg <%d, %d>: %d!\n",
					    link_co_err, msg_user(hdr),
					    msg_type(hdr), msg_size(hdr));
			return;
		}

		msg_set_size(&tnlhdr, pktlen + INT_H_SIZE);
		tnlskb = tipc_buf_acquire(pktlen + INT_H_SIZE, GFP_ATOMIC);
		if (!tnlskb) {
			pr_warn("%sunable to send packet\n", link_co_err);
			return;
		}
		skb_copy_to_linear_data(tnlskb, &tnlhdr, INT_H_SIZE);
		skb_copy_to_linear_data_offset(tnlskb, INT_H_SIZE, hdr, pktlen);
		__skb_queue_tail(&tnlq, tnlskb);
	}
	if (queue != &l->backlogq) {
		queue = &l->backlogq;
		goto tnl;
	}

	if (pktcnt_need_update)
		skb_queue_walk(&tnlq, skb) {
			hdr = buf_msg(skb);
			msg_set_msgcnt(hdr, pktcnt);
		}

	tipc_link_xmit(tnl, &tnlq, xmitq);

	if (mtyp == FAILOVER_MSG) {
		tnl->drop_point = l->rcv_nxt;
		tnl->failover_reasm_skb = l->reasm_buf;
		l->reasm_buf = NULL;

		/* Failover the link's deferdq */
		if (unlikely(!skb_queue_empty(fdefq))) {
			pr_warn("Link failover deferdq not empty: %d!\n",
				skb_queue_len(fdefq));
			__skb_queue_purge(fdefq);
		}
		skb_queue_splice_init(&l->deferdq, fdefq);
	}
}