ipv6_addr_copy(&hdr->daddr, first_hop);
skb->priority = sk->sk_priority;
+ skb->mark = sk->sk_mark;
mtu = dst_mtu(dst);
if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) {
return offset;
}
-EXPORT_SYMBOL_GPL(ip6_find_1stfragopt);
static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
{
* or if the skb it not generated by a local socket. (This last
* check should be redundant, but it's free.)
*/
- if (!np || np->pmtudisc >= IPV6_PMTUDISC_DO) {
+ if (!skb->local_df) {
skb->dev = skb->dst->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
if (skb_shinfo(skb)->frag_list) {
int first_len = skb_pagelen(skb);
+ int truesizes = 0;
if (first_len - hlen > mtu ||
((first_len - hlen) & 7) ||
sock_hold(skb->sk);
frag->sk = skb->sk;
frag->destructor = sock_wfree;
- skb->truesize -= frag->truesize;
+ truesizes += frag->truesize;
}
}
first_len = skb_pagelen(skb);
skb->data_len = first_len - skb_headlen(skb);
+ skb->truesize -= truesizes;
skb->len = first_len;
ipv6_hdr(skb)->payload_len = htons(first_len -
sizeof(struct ipv6hdr));
goto out_err_release;
if (ipv6_addr_any(&fl->fl6_src)) {
- err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src);
+ err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev,
+ &fl->fl6_dst, &fl->fl6_src);
if (err)
goto out_err_release;
}
struct flowi fl_gw;
int redirect;
- ifp = ipv6_get_ifaddr(&fl->fl6_src, (*dst)->dev, 1);
+ ifp = ipv6_get_ifaddr(&init_net, &fl->fl6_src,
+ (*dst)->dev, 1);
redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
if (ifp)
tmp_skb->sk = NULL;
}
+ /* Allow local fragmentation. */
+ if (np->pmtudisc < IPV6_PMTUDISC_DO)
+ skb->local_df = 1;
+
ipv6_addr_copy(final_dst, &fl->fl6_dst);
__skb_pull(skb, skb_network_header_len(skb));
if (opt && opt->opt_flen)
ipv6_addr_copy(&hdr->daddr, final_dst);
skb->priority = sk->sk_priority;
+ skb->mark = sk->sk_mark;
skb->dst = dst_clone(&rt->u.dst);
IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);