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);
#endif /*CONFIG_NETFILTER_DEBUG*/
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 /*__LINUX_IP_NETFILTER_H*/
......@@ -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_udp;
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 */
......@@ -20,6 +20,9 @@
#include <linux/if.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <net/sock.h>
#include <net/route.h>
#include <linux/ip.h>
......@@ -683,8 +686,68 @@ int ip_route_me_harder(struct sk_buff **pskb)
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*/
/* This does not belong here, but ipt_REJECT needs it if connection
tracking in use: without this, connection may not be in hash table,
and hence manufactured ICMP or RST packets will not be associated
......
......@@ -969,65 +969,6 @@ icmp_reply_translation(struct sk_buff **pskb,
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)
{
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