/* Processing handlers for ipmr_forward, under rcu_read_lock() */
 
-static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
-                           int in_vifi, struct sk_buff *skb, int vifi)
+static int ipmr_prepare_xmit(struct net *net, struct mr_table *mrt,
+                            struct sk_buff *skb, int vifi)
 {
        const struct iphdr *iph = ip_hdr(skb);
        struct vif_device *vif = &mrt->vif_table[vifi];
 
        vif_dev = vif_dev_read(vif);
        if (!vif_dev)
-               goto out_free;
+               return -1;
 
        if (vif->flags & VIFF_REGISTER) {
                WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
                DEV_STATS_ADD(vif_dev, tx_bytes, skb->len);
                DEV_STATS_INC(vif_dev, tx_packets);
                ipmr_cache_report(mrt, skb, vifi, IGMPMSG_WHOLEPKT);
-               goto out_free;
+               return -1;
        }
 
-       if (ipmr_forward_offloaded(skb, mrt, in_vifi, vifi))
-               goto out_free;
-
        if (vif->flags & VIFF_TUNNEL) {
                rt = ip_route_output_ports(net, &fl4, NULL,
                                           vif->remote, vif->local,
                                           IPPROTO_IPIP,
                                           iph->tos & INET_DSCP_MASK, vif->link);
                if (IS_ERR(rt))
-                       goto out_free;
+                       return -1;
                encap = sizeof(struct iphdr);
        } else {
                rt = ip_route_output_ports(net, &fl4, NULL, iph->daddr, 0,
                                           IPPROTO_IPIP,
                                           iph->tos & INET_DSCP_MASK, vif->link);
                if (IS_ERR(rt))
-                       goto out_free;
+                       return -1;
        }
 
        if (skb->len+encap > dst_mtu(&rt->dst) && (ntohs(iph->frag_off) & IP_DF)) {
                 */
                IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
                ip_rt_put(rt);
-               goto out_free;
+               return -1;
        }
 
        encap += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len;
 
        if (skb_cow(skb, encap)) {
                ip_rt_put(rt);
-               goto out_free;
+               return -1;
        }
 
        WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
                DEV_STATS_ADD(vif_dev, tx_bytes, skb->len);
        }
 
+       return 0;
+}
+
+static void ipmr_queue_fwd_xmit(struct net *net, struct mr_table *mrt,
+                               int in_vifi, struct sk_buff *skb, int vifi)
+{
+       struct rtable *rt;
+
+       if (ipmr_forward_offloaded(skb, mrt, in_vifi, vifi))
+               goto out_free;
+
+       if (ipmr_prepare_xmit(net, mrt, skb, vifi))
+               goto out_free;
+
+       rt = skb_rtable(skb);
+
        IPCB(skb)->flags |= IPSKB_FORWARDED;
 
        /* RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
                                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
                                if (skb2)
-                                       ipmr_queue_xmit(net, mrt, true_vifi,
-                                                       skb2, psend);
+                                       ipmr_queue_fwd_xmit(net, mrt, true_vifi,
+                                                           skb2, psend);
                        }
                        psend = ct;
                }
                        struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
                        if (skb2)
-                               ipmr_queue_xmit(net, mrt, true_vifi, skb2,
-                                               psend);
+                               ipmr_queue_fwd_xmit(net, mrt, true_vifi, skb2,
+                                                   psend);
                } else {
-                       ipmr_queue_xmit(net, mrt, true_vifi, skb, psend);
+                       ipmr_queue_fwd_xmit(net, mrt, true_vifi, skb, psend);
                        return;
                }
        }