|
@@ -83,6 +83,9 @@
|
|
int sysctl_ip_default_ttl __read_mostly = IPDEFTTL;
|
|
int sysctl_ip_default_ttl __read_mostly = IPDEFTTL;
|
|
EXPORT_SYMBOL(sysctl_ip_default_ttl);
|
|
EXPORT_SYMBOL(sysctl_ip_default_ttl);
|
|
|
|
|
|
|
|
+static int ip_fragment(struct sock *sk, struct sk_buff *skb,
|
|
|
|
+ int (*output)(struct sock *, struct sk_buff *));
|
|
|
|
+
|
|
/* Generate a checksum for an outgoing IP datagram. */
|
|
/* Generate a checksum for an outgoing IP datagram. */
|
|
void ip_send_check(struct iphdr *iph)
|
|
void ip_send_check(struct iphdr *iph)
|
|
{
|
|
{
|
|
@@ -478,6 +481,28 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
|
|
skb_copy_secmark(to, from);
|
|
skb_copy_secmark(to, from);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int ip_fragment(struct sock *sk, struct sk_buff *skb,
|
|
|
|
+ int (*output)(struct sock *, struct sk_buff *))
|
|
|
|
+{
|
|
|
|
+ struct iphdr *iph = ip_hdr(skb);
|
|
|
|
+ unsigned int mtu = ip_skb_dst_mtu(skb);
|
|
|
|
+
|
|
|
|
+ if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) ||
|
|
|
|
+ (IPCB(skb)->frag_max_size &&
|
|
|
|
+ IPCB(skb)->frag_max_size > mtu))) {
|
|
|
|
+ struct rtable *rt = skb_rtable(skb);
|
|
|
|
+ struct net_device *dev = rt->dst.dev;
|
|
|
|
+
|
|
|
|
+ IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
|
|
|
|
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
|
|
|
|
+ htonl(mtu));
|
|
|
|
+ kfree_skb(skb);
|
|
|
|
+ return -EMSGSIZE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ip_do_fragment(sk, skb, output);
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* This IP datagram is too large to be sent in one piece. Break it up into
|
|
* This IP datagram is too large to be sent in one piece. Break it up into
|
|
* smaller pieces (each of size equal to IP header plus
|
|
* smaller pieces (each of size equal to IP header plus
|
|
@@ -485,8 +510,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
|
|
* single device frame, and queue such a frame for sending.
|
|
* single device frame, and queue such a frame for sending.
|
|
*/
|
|
*/
|
|
|
|
|
|
-int ip_fragment(struct sock *sk, struct sk_buff *skb,
|
|
|
|
- int (*output)(struct sock *, struct sk_buff *))
|
|
|
|
|
|
+int ip_do_fragment(struct sock *sk, struct sk_buff *skb,
|
|
|
|
+ int (*output)(struct sock *, struct sk_buff *))
|
|
{
|
|
{
|
|
struct iphdr *iph;
|
|
struct iphdr *iph;
|
|
int ptr;
|
|
int ptr;
|
|
@@ -507,15 +532,6 @@ int ip_fragment(struct sock *sk, struct sk_buff *skb,
|
|
iph = ip_hdr(skb);
|
|
iph = ip_hdr(skb);
|
|
|
|
|
|
mtu = ip_skb_dst_mtu(skb);
|
|
mtu = ip_skb_dst_mtu(skb);
|
|
- if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) ||
|
|
|
|
- (IPCB(skb)->frag_max_size &&
|
|
|
|
- IPCB(skb)->frag_max_size > mtu))) {
|
|
|
|
- IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
|
|
|
|
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
|
|
|
|
- htonl(mtu));
|
|
|
|
- kfree_skb(skb);
|
|
|
|
- return -EMSGSIZE;
|
|
|
|
- }
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* Setup starting values.
|
|
* Setup starting values.
|
|
@@ -751,7 +767,7 @@ fail:
|
|
IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
|
|
IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
-EXPORT_SYMBOL(ip_fragment);
|
|
|
|
|
|
+EXPORT_SYMBOL(ip_do_fragment);
|
|
|
|
|
|
int
|
|
int
|
|
ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
|
|
ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
|