Commit 2dd7b159 authored by Rusty Russell's avatar Rusty Russell Committed by David S. Miller

[NETFILTER]: Move skb_ip_make_writable to netfilter.c.

parent f868da7c
...@@ -75,6 +75,12 @@ void nf_debug_ip_finish_output2(struct sk_buff *skb); ...@@ -75,6 +75,12 @@ void nf_debug_ip_finish_output2(struct sk_buff *skb);
#endif /*CONFIG_NETFILTER_DEBUG*/ #endif /*CONFIG_NETFILTER_DEBUG*/
extern int ip_route_me_harder(struct sk_buff **pskb); extern int ip_route_me_harder(struct sk_buff **pskb);
/* Call this before modifying an existing IP packet: ensures it is
modifiable and linear to the point you care about (writable_len).
Returns true or false. */
extern int skb_ip_make_writable(struct sk_buff **pskb,
unsigned int writable_len);
#endif /*__KERNEL__*/ #endif /*__KERNEL__*/
#endif /*__LINUX_IP_NETFILTER_H*/ #endif /*__LINUX_IP_NETFILTER_H*/
...@@ -30,10 +30,4 @@ extern void place_in_hashes(struct ip_conntrack *conntrack, ...@@ -30,10 +30,4 @@ extern void place_in_hashes(struct ip_conntrack *conntrack,
extern struct ip_nat_protocol ip_nat_protocol_tcp; extern struct ip_nat_protocol ip_nat_protocol_tcp;
extern struct ip_nat_protocol ip_nat_protocol_udp; extern struct ip_nat_protocol ip_nat_protocol_udp;
extern struct ip_nat_protocol ip_nat_protocol_icmp; extern struct ip_nat_protocol ip_nat_protocol_icmp;
/* Call this before modifying an existing IP packet: ensures it is
modifiable and linear to the point you care about (writable_len).
Returns true or false. */
extern int skb_ip_make_writable(struct sk_buff **pskb,
unsigned int writable_len);
#endif /* _IP_NAT_CORE_H */ #endif /* _IP_NAT_CORE_H */
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
#include <linux/if.h> #include <linux/if.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/route.h> #include <net/route.h>
#include <linux/ip.h> #include <linux/ip.h>
...@@ -683,8 +686,68 @@ int ip_route_me_harder(struct sk_buff **pskb) ...@@ -683,8 +686,68 @@ int ip_route_me_harder(struct sk_buff **pskb)
return err; return err;
} }
int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
{
struct sk_buff *nskb;
unsigned int iplen;
if (writable_len > (*pskb)->len)
return 0;
/* Not exclusive use of packet? Must copy. */
if (skb_shared(*pskb) || skb_cloned(*pskb))
goto copy_skb;
/* Alexey says IP hdr is always modifiable and linear, so ok. */
if (writable_len <= (*pskb)->nh.iph->ihl*4)
return 1;
iplen = writable_len - (*pskb)->nh.iph->ihl*4;
/* DaveM says protocol headers are also modifiable. */
switch ((*pskb)->nh.iph->protocol) {
case IPPROTO_TCP: {
struct tcphdr hdr;
if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
&hdr, sizeof(hdr)) != 0)
goto copy_skb;
if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
goto pull_skb;
goto copy_skb;
}
case IPPROTO_UDP:
if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
goto pull_skb;
goto copy_skb;
case IPPROTO_ICMP:
if (writable_len
<= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
goto pull_skb;
goto copy_skb;
/* Insert other cases here as desired */
}
copy_skb:
nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return 0;
BUG_ON(skb_is_nonlinear(nskb));
/* Rest of kernel will get very unhappy if we pass it a
suddenly-orphaned skbuff */
if ((*pskb)->sk)
skb_set_owner_w(nskb, (*pskb)->sk);
kfree_skb(*pskb);
*pskb = nskb;
return 1;
pull_skb:
return pskb_may_pull(*pskb, writable_len);
}
#endif /*CONFIG_INET*/ #endif /*CONFIG_INET*/
/* This does not belong here, but ipt_REJECT needs it if connection /* This does not belong here, but ipt_REJECT needs it if connection
tracking in use: without this, connection may not be in hash table, tracking in use: without this, connection may not be in hash table,
and hence manufactured ICMP or RST packets will not be associated and hence manufactured ICMP or RST packets will not be associated
......
...@@ -969,65 +969,6 @@ icmp_reply_translation(struct sk_buff **pskb, ...@@ -969,65 +969,6 @@ icmp_reply_translation(struct sk_buff **pskb,
return 0; return 0;
} }
int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
{
struct sk_buff *nskb;
unsigned int iplen;
if (writable_len > (*pskb)->len)
return 0;
/* Not exclusive use of packet? Must copy. */
if (skb_shared(*pskb) || skb_cloned(*pskb))
goto copy_skb;
/* Alexey says IP hdr is always modifiable and linear, so ok. */
if (writable_len <= (*pskb)->nh.iph->ihl*4)
return 1;
iplen = writable_len - (*pskb)->nh.iph->ihl*4;
/* DaveM says protocol headers are also modifiable. */
switch ((*pskb)->nh.iph->protocol) {
case IPPROTO_TCP: {
struct tcphdr hdr;
if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
&hdr, sizeof(hdr)) != 0)
goto copy_skb;
if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
goto pull_skb;
goto copy_skb;
}
case IPPROTO_UDP:
if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
goto pull_skb;
goto copy_skb;
case IPPROTO_ICMP:
if (writable_len
<= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
goto pull_skb;
goto copy_skb;
/* Insert other cases here as desired */
}
copy_skb:
nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return 0;
BUG_ON(skb_is_nonlinear(nskb));
/* Rest of kernel will get very unhappy if we pass it a
suddenly-orphaned skbuff */
if ((*pskb)->sk)
skb_set_owner_w(nskb, (*pskb)->sk);
kfree_skb(*pskb);
*pskb = nskb;
return 1;
pull_skb:
return pskb_may_pull(*pskb, writable_len);
}
int __init ip_nat_init(void) int __init ip_nat_init(void)
{ {
size_t i; size_t i;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment