[NETFILTER]: Avoid skb_copy/pskb_copy/skb_realloc_headroom
This patch replaces unnecessary uses of skb_copy, pskb_copy and skb_realloc_headroom by functions such as skb_make_writable and pskb_expand_head. This allows us to remove the double pointers later. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
af1e1cf073
commit
2ca7b0ac02
@@ -8,6 +8,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter_bridge/ebtables.h>
|
#include <linux/netfilter_bridge/ebtables.h>
|
||||||
#include <linux/netfilter_bridge/ebt_nat.h>
|
#include <linux/netfilter_bridge/ebt_nat.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -19,17 +20,9 @@ static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr,
|
|||||||
{
|
{
|
||||||
struct ebt_nat_info *info = (struct ebt_nat_info *)data;
|
struct ebt_nat_info *info = (struct ebt_nat_info *)data;
|
||||||
|
|
||||||
if (skb_shared(*pskb) || skb_cloned(*pskb)) {
|
if (skb_make_writable(*pskb, 0))
|
||||||
struct sk_buff *nskb;
|
return NF_DROP;
|
||||||
|
|
||||||
nskb = skb_copy(*pskb, GFP_ATOMIC);
|
|
||||||
if (!nskb)
|
|
||||||
return NF_DROP;
|
|
||||||
if ((*pskb)->sk)
|
|
||||||
skb_set_owner_w(nskb, (*pskb)->sk);
|
|
||||||
kfree_skb(*pskb);
|
|
||||||
*pskb = nskb;
|
|
||||||
}
|
|
||||||
memcpy(eth_hdr(*pskb)->h_dest, info->mac, ETH_ALEN);
|
memcpy(eth_hdr(*pskb)->h_dest, info->mac, ETH_ALEN);
|
||||||
return info->target;
|
return info->target;
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter_bridge/ebtables.h>
|
#include <linux/netfilter_bridge/ebtables.h>
|
||||||
#include <linux/netfilter_bridge/ebt_redirect.h>
|
#include <linux/netfilter_bridge/ebt_redirect.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -20,17 +21,9 @@ static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr,
|
|||||||
{
|
{
|
||||||
struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
|
struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
|
||||||
|
|
||||||
if (skb_shared(*pskb) || skb_cloned(*pskb)) {
|
if (skb_make_writable(*pskb, 0))
|
||||||
struct sk_buff *nskb;
|
return NF_DROP;
|
||||||
|
|
||||||
nskb = skb_copy(*pskb, GFP_ATOMIC);
|
|
||||||
if (!nskb)
|
|
||||||
return NF_DROP;
|
|
||||||
if ((*pskb)->sk)
|
|
||||||
skb_set_owner_w(nskb, (*pskb)->sk);
|
|
||||||
kfree_skb(*pskb);
|
|
||||||
*pskb = nskb;
|
|
||||||
}
|
|
||||||
if (hooknr != NF_BR_BROUTING)
|
if (hooknr != NF_BR_BROUTING)
|
||||||
memcpy(eth_hdr(*pskb)->h_dest,
|
memcpy(eth_hdr(*pskb)->h_dest,
|
||||||
in->br_port->br->dev->dev_addr, ETH_ALEN);
|
in->br_port->br->dev->dev_addr, ETH_ALEN);
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter_bridge/ebtables.h>
|
#include <linux/netfilter_bridge/ebtables.h>
|
||||||
#include <linux/netfilter_bridge/ebt_nat.h>
|
#include <linux/netfilter_bridge/ebt_nat.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -21,17 +22,9 @@ static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
|
|||||||
{
|
{
|
||||||
struct ebt_nat_info *info = (struct ebt_nat_info *) data;
|
struct ebt_nat_info *info = (struct ebt_nat_info *) data;
|
||||||
|
|
||||||
if (skb_shared(*pskb) || skb_cloned(*pskb)) {
|
if (skb_make_writable(*pskb, 0))
|
||||||
struct sk_buff *nskb;
|
return NF_DROP;
|
||||||
|
|
||||||
nskb = skb_copy(*pskb, GFP_ATOMIC);
|
|
||||||
if (!nskb)
|
|
||||||
return NF_DROP;
|
|
||||||
if ((*pskb)->sk)
|
|
||||||
skb_set_owner_w(nskb, (*pskb)->sk);
|
|
||||||
kfree_skb(*pskb);
|
|
||||||
*pskb = nskb;
|
|
||||||
}
|
|
||||||
memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN);
|
memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN);
|
||||||
if (!(info->target & NAT_ARP_BIT) &&
|
if (!(info->target & NAT_ARP_BIT) &&
|
||||||
eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) {
|
eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) {
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter_ipv4.h>
|
#include <linux/netfilter_ipv4.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
#include <net/route.h>
|
#include <net/route.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
@@ -66,17 +67,10 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
|
|||||||
|
|
||||||
/* Change in oif may mean change in hh_len. */
|
/* Change in oif may mean change in hh_len. */
|
||||||
hh_len = (*pskb)->dst->dev->hard_header_len;
|
hh_len = (*pskb)->dst->dev->hard_header_len;
|
||||||
if (skb_headroom(*pskb) < hh_len) {
|
if (skb_headroom(*pskb) < hh_len &&
|
||||||
struct sk_buff *nskb;
|
pskb_expand_head(*pskb, hh_len - skb_headroom(*pskb), 0,
|
||||||
|
GFP_ATOMIC))
|
||||||
nskb = skb_realloc_headroom(*pskb, hh_len);
|
return -1;
|
||||||
if (!nskb)
|
|
||||||
return -1;
|
|
||||||
if ((*pskb)->sk)
|
|
||||||
skb_set_owner_w(nskb, (*pskb)->sk);
|
|
||||||
kfree_skb(*pskb);
|
|
||||||
*pskb = nskb;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -107,17 +101,10 @@ int ip_xfrm_me_harder(struct sk_buff **pskb)
|
|||||||
|
|
||||||
/* Change in oif may mean change in hh_len. */
|
/* Change in oif may mean change in hh_len. */
|
||||||
hh_len = (*pskb)->dst->dev->hard_header_len;
|
hh_len = (*pskb)->dst->dev->hard_header_len;
|
||||||
if (skb_headroom(*pskb) < hh_len) {
|
if (skb_headroom(*pskb) < hh_len &&
|
||||||
struct sk_buff *nskb;
|
pskb_expand_head(*pskb, hh_len - skb_headroom(*pskb), 0,
|
||||||
|
GFP_ATOMIC))
|
||||||
nskb = skb_realloc_headroom(*pskb, hh_len);
|
return -1;
|
||||||
if (!nskb)
|
|
||||||
return -1;
|
|
||||||
if ((*pskb)->sk)
|
|
||||||
skb_set_owner_w(nskb, (*pskb)->sk);
|
|
||||||
kfree_skb(*pskb);
|
|
||||||
*pskb = nskb;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ip_xfrm_me_harder);
|
EXPORT_SYMBOL(ip_xfrm_me_harder);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
/* module that allows mangling of the arp payload */
|
/* module that allows mangling of the arp payload */
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/netfilter.h>
|
||||||
#include <linux/netfilter_arp/arpt_mangle.h>
|
#include <linux/netfilter_arp/arpt_mangle.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
|
|
||||||
@@ -18,17 +19,8 @@ target(struct sk_buff **pskb,
|
|||||||
unsigned char *arpptr;
|
unsigned char *arpptr;
|
||||||
int pln, hln;
|
int pln, hln;
|
||||||
|
|
||||||
if (skb_shared(*pskb) || skb_cloned(*pskb)) {
|
if (skb_make_writable(*pskb, (*pskb)->len))
|
||||||
struct sk_buff *nskb;
|
return NF_DROP;
|
||||||
|
|
||||||
nskb = skb_copy(*pskb, GFP_ATOMIC);
|
|
||||||
if (!nskb)
|
|
||||||
return NF_DROP;
|
|
||||||
if ((*pskb)->sk)
|
|
||||||
skb_set_owner_w(nskb, (*pskb)->sk);
|
|
||||||
kfree_skb(*pskb);
|
|
||||||
*pskb = nskb;
|
|
||||||
}
|
|
||||||
|
|
||||||
arp = arp_hdr(*pskb);
|
arp = arp_hdr(*pskb);
|
||||||
arpptr = skb_network_header(*pskb) + sizeof(*arp);
|
arpptr = skb_network_header(*pskb) + sizeof(*arp);
|
||||||
|
@@ -335,6 +335,7 @@ static int
|
|||||||
ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
|
ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
|
||||||
{
|
{
|
||||||
int diff;
|
int diff;
|
||||||
|
int err;
|
||||||
struct iphdr *user_iph = (struct iphdr *)v->payload;
|
struct iphdr *user_iph = (struct iphdr *)v->payload;
|
||||||
|
|
||||||
if (v->data_len < sizeof(*user_iph))
|
if (v->data_len < sizeof(*user_iph))
|
||||||
@@ -347,21 +348,14 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
|
|||||||
if (v->data_len > 0xFFFF)
|
if (v->data_len > 0xFFFF)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (diff > skb_tailroom(e->skb)) {
|
if (diff > skb_tailroom(e->skb)) {
|
||||||
struct sk_buff *newskb;
|
err = pskb_expand_head(e->skb, 0,
|
||||||
|
diff - skb_tailroom(e->skb),
|
||||||
newskb = skb_copy_expand(e->skb,
|
GFP_ATOMIC);
|
||||||
skb_headroom(e->skb),
|
if (err) {
|
||||||
diff,
|
printk(KERN_WARNING "ip_queue: error "
|
||||||
GFP_ATOMIC);
|
"in mangle, dropping packet: %d\n", -err);
|
||||||
if (newskb == NULL) {
|
return err;
|
||||||
printk(KERN_WARNING "ip_queue: OOM "
|
|
||||||
"in mangle, dropping packet\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
if (e->skb->sk)
|
|
||||||
skb_set_owner_w(newskb, e->skb->sk);
|
|
||||||
kfree_skb(e->skb);
|
|
||||||
e->skb = newskb;
|
|
||||||
}
|
}
|
||||||
skb_put(e->skb, diff);
|
skb_put(e->skb, diff);
|
||||||
}
|
}
|
||||||
|
@@ -113,20 +113,12 @@ static void mangle_contents(struct sk_buff *skb,
|
|||||||
/* Unusual, but possible case. */
|
/* Unusual, but possible case. */
|
||||||
static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
|
static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
|
||||||
{
|
{
|
||||||
struct sk_buff *nskb;
|
|
||||||
|
|
||||||
if ((*pskb)->len + extra > 65535)
|
if ((*pskb)->len + extra > 65535)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC);
|
if (pskb_expand_head(*pskb, 0, extra - skb_tailroom(*pskb), GFP_ATOMIC))
|
||||||
if (!nskb)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Transfer socket to new skb. */
|
|
||||||
if ((*pskb)->sk)
|
|
||||||
skb_set_owner_w(nskb, (*pskb)->sk);
|
|
||||||
kfree_skb(*pskb);
|
|
||||||
*pskb = nskb;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -332,6 +332,7 @@ static int
|
|||||||
ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
|
ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
|
||||||
{
|
{
|
||||||
int diff;
|
int diff;
|
||||||
|
int err;
|
||||||
struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
|
struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
|
||||||
|
|
||||||
if (v->data_len < sizeof(*user_iph))
|
if (v->data_len < sizeof(*user_iph))
|
||||||
@@ -344,21 +345,14 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
|
|||||||
if (v->data_len > 0xFFFF)
|
if (v->data_len > 0xFFFF)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (diff > skb_tailroom(e->skb)) {
|
if (diff > skb_tailroom(e->skb)) {
|
||||||
struct sk_buff *newskb;
|
err = pskb_expand_head(e->skb, 0,
|
||||||
|
diff - skb_tailroom(e->skb),
|
||||||
newskb = skb_copy_expand(e->skb,
|
GFP_ATOMIC);
|
||||||
skb_headroom(e->skb),
|
if (err) {
|
||||||
diff,
|
|
||||||
GFP_ATOMIC);
|
|
||||||
if (newskb == NULL) {
|
|
||||||
printk(KERN_WARNING "ip6_queue: OOM "
|
printk(KERN_WARNING "ip6_queue: OOM "
|
||||||
"in mangle, dropping packet\n");
|
"in mangle, dropping packet\n");
|
||||||
return -ENOMEM;
|
return err;
|
||||||
}
|
}
|
||||||
if (e->skb->sk)
|
|
||||||
skb_set_owner_w(newskb, e->skb->sk);
|
|
||||||
kfree_skb(e->skb);
|
|
||||||
e->skb = newskb;
|
|
||||||
}
|
}
|
||||||
skb_put(e->skb, diff);
|
skb_put(e->skb, diff);
|
||||||
}
|
}
|
||||||
|
@@ -617,6 +617,7 @@ static int
|
|||||||
nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e)
|
nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e)
|
||||||
{
|
{
|
||||||
int diff;
|
int diff;
|
||||||
|
int err;
|
||||||
|
|
||||||
diff = data_len - e->skb->len;
|
diff = data_len - e->skb->len;
|
||||||
if (diff < 0) {
|
if (diff < 0) {
|
||||||
@@ -626,21 +627,14 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e)
|
|||||||
if (data_len > 0xFFFF)
|
if (data_len > 0xFFFF)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (diff > skb_tailroom(e->skb)) {
|
if (diff > skb_tailroom(e->skb)) {
|
||||||
struct sk_buff *newskb;
|
err = pskb_expand_head(e->skb, 0,
|
||||||
|
diff - skb_tailroom(e->skb),
|
||||||
newskb = skb_copy_expand(e->skb,
|
GFP_ATOMIC);
|
||||||
skb_headroom(e->skb),
|
if (err) {
|
||||||
diff,
|
|
||||||
GFP_ATOMIC);
|
|
||||||
if (newskb == NULL) {
|
|
||||||
printk(KERN_WARNING "nf_queue: OOM "
|
printk(KERN_WARNING "nf_queue: OOM "
|
||||||
"in mangle, dropping packet\n");
|
"in mangle, dropping packet\n");
|
||||||
return -ENOMEM;
|
return err;
|
||||||
}
|
}
|
||||||
if (e->skb->sk)
|
|
||||||
skb_set_owner_w(newskb, e->skb->sk);
|
|
||||||
kfree_skb(e->skb);
|
|
||||||
e->skb = newskb;
|
|
||||||
}
|
}
|
||||||
skb_put(e->skb, diff);
|
skb_put(e->skb, diff);
|
||||||
}
|
}
|
||||||
|
@@ -105,14 +105,10 @@ tcpmss_mangle_packet(struct sk_buff **pskb,
|
|||||||
* MSS Option not found ?! add it..
|
* MSS Option not found ?! add it..
|
||||||
*/
|
*/
|
||||||
if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
|
if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
|
||||||
struct sk_buff *newskb;
|
if (pskb_expand_head(*pskb, 0,
|
||||||
|
TCPOLEN_MSS - skb_tailroom(*pskb),
|
||||||
newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
|
GFP_ATOMIC))
|
||||||
TCPOLEN_MSS, GFP_ATOMIC);
|
|
||||||
if (!newskb)
|
|
||||||
return -1;
|
return -1;
|
||||||
kfree_skb(*pskb);
|
|
||||||
*pskb = newskb;
|
|
||||||
tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff);
|
tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user