summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter_bridge.h7
-rw-r--r--net/bridge/br_netfilter.c2
-rw-r--r--net/ipv4/ip_output.c4
3 files changed, 12 insertions, 1 deletions
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
index ea0e44b9043..0ddd161f3b0 100644
--- a/include/linux/netfilter_bridge.h
+++ b/include/linux/netfilter_bridge.h
@@ -68,6 +68,13 @@ static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb)
}
}
+static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb)
+{
+ if (unlikely(skb->nf_bridge->mask & BRNF_PPPoE))
+ return PPPOE_SES_HLEN;
+ return 0;
+}
+
extern int br_handle_frame_finish(struct sk_buff *skb);
/* Only used in br_device.c */
static inline int br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 6b80ebc3766..93f80fefa49 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -745,7 +745,7 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb,
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
{
if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) &&
- skb->len > skb->dev->mtu &&
+ skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu &&
!skb_is_gso(skb))
return ip_fragment(skb, br_dev_queue_push_xmit);
else
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index b0b2e3059f1..d979710684b 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -469,6 +469,10 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
hlen = iph->ihl * 4;
mtu = dst_mtu(&rt->u.dst) - hlen; /* Size of data space */
+#ifdef CONFIG_BRIDGE_NETFILTER
+ if (skb->nf_bridge)
+ mtu -= nf_bridge_mtu_reduction(skb);
+#endif
IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE;
/* When frag_list is given, use it. First, check its validity: