Skip to content

Commit

Permalink
ipv4: fix IPSKB_FRAG_PMTU handling with fragmentation
Browse files Browse the repository at this point in the history
This patch removes the iph field from the state structure, which is not
properly initialized. Instead, add a new field to make the "do we want
to set DF" be the state bit and move the code to set the DF flag from
ip_frag_next().

Joint work with Pablo and Linus.

Fixes: 19c3401 ("net: ipv4: place control buffer handling away from fragmentation iterators")
Reported-by: Patrick Schönthaler <patrick@notvads.ovh>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Oct 21, 2019
1 parent 40c5b2b commit e7a409c
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 8 deletions.
4 changes: 2 additions & 2 deletions include/net/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static inline struct sk_buff *ip_fraglist_next(struct ip_fraglist_iter *iter)
}

struct ip_frag_state {
struct iphdr *iph;
bool DF;
unsigned int hlen;
unsigned int ll_rs;
unsigned int mtu;
Expand All @@ -196,7 +196,7 @@ struct ip_frag_state {
};

void ip_frag_init(struct sk_buff *skb, unsigned int hlen, unsigned int ll_rs,
unsigned int mtu, struct ip_frag_state *state);
unsigned int mtu, bool DF, struct ip_frag_state *state);
struct sk_buff *ip_frag_next(struct sk_buff *skb,
struct ip_frag_state *state);

Expand Down
2 changes: 1 addition & 1 deletion net/bridge/netfilter/nf_conntrack_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ static int nf_br_ip_fragment(struct net *net, struct sock *sk,
* This may also be a clone skbuff, we could preserve the geometry for
* the copies but probably not worth the effort.
*/
ip_frag_init(skb, hlen, ll_rs, frag_max_size, &state);
ip_frag_init(skb, hlen, ll_rs, frag_max_size, false, &state);

while (state.left > 0) {
struct sk_buff *skb2;
Expand Down
11 changes: 6 additions & 5 deletions net/ipv4/ip_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,11 +645,12 @@ void ip_fraglist_prepare(struct sk_buff *skb, struct ip_fraglist_iter *iter)
EXPORT_SYMBOL(ip_fraglist_prepare);

void ip_frag_init(struct sk_buff *skb, unsigned int hlen,
unsigned int ll_rs, unsigned int mtu,
unsigned int ll_rs, unsigned int mtu, bool DF,
struct ip_frag_state *state)
{
struct iphdr *iph = ip_hdr(skb);

state->DF = DF;
state->hlen = hlen;
state->ll_rs = ll_rs;
state->mtu = mtu;
Expand All @@ -668,9 +669,6 @@ static void ip_frag_ipcb(struct sk_buff *from, struct sk_buff *to,
/* Copy the flags to each fragment. */
IPCB(to)->flags = IPCB(from)->flags;

if (IPCB(from)->flags & IPSKB_FRAG_PMTU)
state->iph->frag_off |= htons(IP_DF);

/* ANK: dirty, but effective trick. Upgrade options only if
* the segment to be fragmented was THE FIRST (otherwise,
* options are already fixed) and make it ONCE
Expand Down Expand Up @@ -738,6 +736,8 @@ struct sk_buff *ip_frag_next(struct sk_buff *skb, struct ip_frag_state *state)
*/
iph = ip_hdr(skb2);
iph->frag_off = htons((state->offset >> 3));
if (state->DF)
iph->frag_off |= htons(IP_DF);

/*
* Added AC : If we are fragmenting a fragment that's not the
Expand Down Expand Up @@ -883,7 +883,8 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
* Fragment the datagram.
*/

ip_frag_init(skb, hlen, ll_rs, mtu, &state);
ip_frag_init(skb, hlen, ll_rs, mtu, IPCB(skb)->flags & IPSKB_FRAG_PMTU,
&state);

/*
* Keep copying data until we run out.
Expand Down

0 comments on commit e7a409c

Please sign in to comment.