diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-10-14 03:39:55 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-15 15:26:28 -0400 |
commit | 2ca7b0ac022aa0158599178fe1056b1ba9ec8b97 (patch) | |
tree | 6eece25447f0ec3b5d5f5533e49e10fde4d59f35 | |
parent | af1e1cf073e3d038b7aac417a20585ecdcab7de6 (diff) |
[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>
-rw-r--r-- | net/bridge/netfilter/ebt_dnat.c | 13 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_redirect.c | 13 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_snat.c | 13 | ||||
-rw-r--r-- | net/ipv4/netfilter.c | 31 | ||||
-rw-r--r-- | net/ipv4/netfilter/arpt_mangle.c | 14 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 22 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_helper.c | 10 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 18 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue.c | 18 | ||||
-rw-r--r-- | net/netfilter/xt_TCPMSS.c | 10 |
10 files changed, 45 insertions, 117 deletions
diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c index 4582659dff0e..9d74dee20ab0 100644 --- a/net/bridge/netfilter/ebt_dnat.c +++ b/net/bridge/netfilter/ebt_dnat.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/netfilter.h> | ||
11 | #include <linux/netfilter_bridge/ebtables.h> | 12 | #include <linux/netfilter_bridge/ebtables.h> |
12 | #include <linux/netfilter_bridge/ebt_nat.h> | 13 | #include <linux/netfilter_bridge/ebt_nat.h> |
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
@@ -19,17 +20,9 @@ static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr, | |||
19 | { | 20 | { |
20 | struct ebt_nat_info *info = (struct ebt_nat_info *)data; | 21 | struct ebt_nat_info *info = (struct ebt_nat_info *)data; |
21 | 22 | ||
22 | if (skb_shared(*pskb) || skb_cloned(*pskb)) { | 23 | if (skb_make_writable(*pskb, 0)) |
23 | struct sk_buff *nskb; | 24 | return NF_DROP; |
24 | 25 | ||
25 | nskb = skb_copy(*pskb, GFP_ATOMIC); | ||
26 | if (!nskb) | ||
27 | return NF_DROP; | ||
28 | if ((*pskb)->sk) | ||
29 | skb_set_owner_w(nskb, (*pskb)->sk); | ||
30 | kfree_skb(*pskb); | ||
31 | *pskb = nskb; | ||
32 | } | ||
33 | memcpy(eth_hdr(*pskb)->h_dest, info->mac, ETH_ALEN); | 26 | memcpy(eth_hdr(*pskb)->h_dest, info->mac, ETH_ALEN); |
34 | return info->target; | 27 | return info->target; |
35 | } | 28 | } |
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index 9f378eab72d0..81371cd01bd0 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/netfilter.h> | ||
11 | #include <linux/netfilter_bridge/ebtables.h> | 12 | #include <linux/netfilter_bridge/ebtables.h> |
12 | #include <linux/netfilter_bridge/ebt_redirect.h> | 13 | #include <linux/netfilter_bridge/ebt_redirect.h> |
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
@@ -20,17 +21,9 @@ static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr, | |||
20 | { | 21 | { |
21 | struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; | 22 | struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; |
22 | 23 | ||
23 | if (skb_shared(*pskb) || skb_cloned(*pskb)) { | 24 | if (skb_make_writable(*pskb, 0)) |
24 | struct sk_buff *nskb; | 25 | return NF_DROP; |
25 | 26 | ||
26 | nskb = skb_copy(*pskb, GFP_ATOMIC); | ||
27 | if (!nskb) | ||
28 | return NF_DROP; | ||
29 | if ((*pskb)->sk) | ||
30 | skb_set_owner_w(nskb, (*pskb)->sk); | ||
31 | kfree_skb(*pskb); | ||
32 | *pskb = nskb; | ||
33 | } | ||
34 | if (hooknr != NF_BR_BROUTING) | 27 | if (hooknr != NF_BR_BROUTING) |
35 | memcpy(eth_hdr(*pskb)->h_dest, | 28 | memcpy(eth_hdr(*pskb)->h_dest, |
36 | in->br_port->br->dev->dev_addr, ETH_ALEN); | 29 | in->br_port->br->dev->dev_addr, ETH_ALEN); |
diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c index a50722182bfe..b0c63684e2f5 100644 --- a/net/bridge/netfilter/ebt_snat.c +++ b/net/bridge/netfilter/ebt_snat.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/netfilter.h> | ||
11 | #include <linux/netfilter_bridge/ebtables.h> | 12 | #include <linux/netfilter_bridge/ebtables.h> |
12 | #include <linux/netfilter_bridge/ebt_nat.h> | 13 | #include <linux/netfilter_bridge/ebt_nat.h> |
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
@@ -21,17 +22,9 @@ static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr, | |||
21 | { | 22 | { |
22 | struct ebt_nat_info *info = (struct ebt_nat_info *) data; | 23 | struct ebt_nat_info *info = (struct ebt_nat_info *) data; |
23 | 24 | ||
24 | if (skb_shared(*pskb) || skb_cloned(*pskb)) { | 25 | if (skb_make_writable(*pskb, 0)) |
25 | struct sk_buff *nskb; | 26 | return NF_DROP; |
26 | 27 | ||
27 | nskb = skb_copy(*pskb, GFP_ATOMIC); | ||
28 | if (!nskb) | ||
29 | return NF_DROP; | ||
30 | if ((*pskb)->sk) | ||
31 | skb_set_owner_w(nskb, (*pskb)->sk); | ||
32 | kfree_skb(*pskb); | ||
33 | *pskb = nskb; | ||
34 | } | ||
35 | memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN); | 28 | memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN); |
36 | if (!(info->target & NAT_ARP_BIT) && | 29 | if (!(info->target & NAT_ARP_BIT) && |
37 | eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) { | 30 | eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) { |
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index b44192924f95..d1e3012d891f 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/netfilter.h> | 3 | #include <linux/netfilter.h> |
4 | #include <linux/netfilter_ipv4.h> | 4 | #include <linux/netfilter_ipv4.h> |
5 | #include <linux/ip.h> | 5 | #include <linux/ip.h> |
6 | #include <linux/skbuff.h> | ||
6 | #include <net/route.h> | 7 | #include <net/route.h> |
7 | #include <net/xfrm.h> | 8 | #include <net/xfrm.h> |
8 | #include <net/ip.h> | 9 | #include <net/ip.h> |
@@ -66,17 +67,10 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) | |||
66 | 67 | ||
67 | /* Change in oif may mean change in hh_len. */ | 68 | /* Change in oif may mean change in hh_len. */ |
68 | hh_len = (*pskb)->dst->dev->hard_header_len; | 69 | hh_len = (*pskb)->dst->dev->hard_header_len; |
69 | if (skb_headroom(*pskb) < hh_len) { | 70 | if (skb_headroom(*pskb) < hh_len && |
70 | struct sk_buff *nskb; | 71 | pskb_expand_head(*pskb, hh_len - skb_headroom(*pskb), 0, |
71 | 72 | GFP_ATOMIC)) | |
72 | nskb = skb_realloc_headroom(*pskb, hh_len); | 73 | return -1; |
73 | if (!nskb) | ||
74 | return -1; | ||
75 | if ((*pskb)->sk) | ||
76 | skb_set_owner_w(nskb, (*pskb)->sk); | ||
77 | kfree_skb(*pskb); | ||
78 | *pskb = nskb; | ||
79 | } | ||
80 | 74 | ||
81 | return 0; | 75 | return 0; |
82 | } | 76 | } |
@@ -107,17 +101,10 @@ int ip_xfrm_me_harder(struct sk_buff **pskb) | |||
107 | 101 | ||
108 | /* Change in oif may mean change in hh_len. */ | 102 | /* Change in oif may mean change in hh_len. */ |
109 | hh_len = (*pskb)->dst->dev->hard_header_len; | 103 | hh_len = (*pskb)->dst->dev->hard_header_len; |
110 | if (skb_headroom(*pskb) < hh_len) { | 104 | if (skb_headroom(*pskb) < hh_len && |
111 | struct sk_buff *nskb; | 105 | pskb_expand_head(*pskb, hh_len - skb_headroom(*pskb), 0, |
112 | 106 | GFP_ATOMIC)) | |
113 | nskb = skb_realloc_headroom(*pskb, hh_len); | 107 | return -1; |
114 | if (!nskb) | ||
115 | return -1; | ||
116 | if ((*pskb)->sk) | ||
117 | skb_set_owner_w(nskb, (*pskb)->sk); | ||
118 | kfree_skb(*pskb); | ||
119 | *pskb = nskb; | ||
120 | } | ||
121 | return 0; | 108 | return 0; |
122 | } | 109 | } |
123 | EXPORT_SYMBOL(ip_xfrm_me_harder); | 110 | EXPORT_SYMBOL(ip_xfrm_me_harder); |
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index c4bdab47597f..0181f919a79c 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* module that allows mangling of the arp payload */ | 1 | /* module that allows mangling of the arp payload */ |
2 | #include <linux/module.h> | 2 | #include <linux/module.h> |
3 | #include <linux/netfilter.h> | ||
3 | #include <linux/netfilter_arp/arpt_mangle.h> | 4 | #include <linux/netfilter_arp/arpt_mangle.h> |
4 | #include <net/sock.h> | 5 | #include <net/sock.h> |
5 | 6 | ||
@@ -18,17 +19,8 @@ target(struct sk_buff **pskb, | |||
18 | unsigned char *arpptr; | 19 | unsigned char *arpptr; |
19 | int pln, hln; | 20 | int pln, hln; |
20 | 21 | ||
21 | if (skb_shared(*pskb) || skb_cloned(*pskb)) { | 22 | if (skb_make_writable(*pskb, (*pskb)->len)) |
22 | struct sk_buff *nskb; | 23 | return NF_DROP; |
23 | |||
24 | nskb = skb_copy(*pskb, GFP_ATOMIC); | ||
25 | if (!nskb) | ||
26 | return NF_DROP; | ||
27 | if ((*pskb)->sk) | ||
28 | skb_set_owner_w(nskb, (*pskb)->sk); | ||
29 | kfree_skb(*pskb); | ||
30 | *pskb = nskb; | ||
31 | } | ||
32 | 24 | ||
33 | arp = arp_hdr(*pskb); | 25 | arp = arp_hdr(*pskb); |
34 | arpptr = skb_network_header(*pskb) + sizeof(*arp); | 26 | arpptr = skb_network_header(*pskb) + sizeof(*arp); |
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 62d8867ca7d0..10a2ce09fd8e 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
@@ -335,6 +335,7 @@ static int | |||
335 | ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) | 335 | ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) |
336 | { | 336 | { |
337 | int diff; | 337 | int diff; |
338 | int err; | ||
338 | struct iphdr *user_iph = (struct iphdr *)v->payload; | 339 | struct iphdr *user_iph = (struct iphdr *)v->payload; |
339 | 340 | ||
340 | if (v->data_len < sizeof(*user_iph)) | 341 | if (v->data_len < sizeof(*user_iph)) |
@@ -347,21 +348,14 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) | |||
347 | if (v->data_len > 0xFFFF) | 348 | if (v->data_len > 0xFFFF) |
348 | return -EINVAL; | 349 | return -EINVAL; |
349 | if (diff > skb_tailroom(e->skb)) { | 350 | if (diff > skb_tailroom(e->skb)) { |
350 | struct sk_buff *newskb; | 351 | err = pskb_expand_head(e->skb, 0, |
351 | 352 | diff - skb_tailroom(e->skb), | |
352 | newskb = skb_copy_expand(e->skb, | 353 | GFP_ATOMIC); |
353 | skb_headroom(e->skb), | 354 | if (err) { |
354 | diff, | 355 | printk(KERN_WARNING "ip_queue: error " |
355 | GFP_ATOMIC); | 356 | "in mangle, dropping packet: %d\n", -err); |
356 | if (newskb == NULL) { | 357 | return err; |
357 | printk(KERN_WARNING "ip_queue: OOM " | ||
358 | "in mangle, dropping packet\n"); | ||
359 | return -ENOMEM; | ||
360 | } | 358 | } |
361 | if (e->skb->sk) | ||
362 | skb_set_owner_w(newskb, e->skb->sk); | ||
363 | kfree_skb(e->skb); | ||
364 | e->skb = newskb; | ||
365 | } | 359 | } |
366 | skb_put(e->skb, diff); | 360 | skb_put(e->skb, diff); |
367 | } | 361 | } |
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 6e81f7612b71..40b429e4540d 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c | |||
@@ -113,20 +113,12 @@ static void mangle_contents(struct sk_buff *skb, | |||
113 | /* Unusual, but possible case. */ | 113 | /* Unusual, but possible case. */ |
114 | static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) | 114 | static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) |
115 | { | 115 | { |
116 | struct sk_buff *nskb; | ||
117 | |||
118 | if ((*pskb)->len + extra > 65535) | 116 | if ((*pskb)->len + extra > 65535) |
119 | return 0; | 117 | return 0; |
120 | 118 | ||
121 | nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); | 119 | if (pskb_expand_head(*pskb, 0, extra - skb_tailroom(*pskb), GFP_ATOMIC)) |
122 | if (!nskb) | ||
123 | return 0; | 120 | return 0; |
124 | 121 | ||
125 | /* Transfer socket to new skb. */ | ||
126 | if ((*pskb)->sk) | ||
127 | skb_set_owner_w(nskb, (*pskb)->sk); | ||
128 | kfree_skb(*pskb); | ||
129 | *pskb = nskb; | ||
130 | return 1; | 122 | return 1; |
131 | } | 123 | } |
132 | 124 | ||
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index d7080dd475ac..6413a30d9f68 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -332,6 +332,7 @@ static int | |||
332 | ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) | 332 | ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) |
333 | { | 333 | { |
334 | int diff; | 334 | int diff; |
335 | int err; | ||
335 | struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; | 336 | struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; |
336 | 337 | ||
337 | if (v->data_len < sizeof(*user_iph)) | 338 | if (v->data_len < sizeof(*user_iph)) |
@@ -344,21 +345,14 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) | |||
344 | if (v->data_len > 0xFFFF) | 345 | if (v->data_len > 0xFFFF) |
345 | return -EINVAL; | 346 | return -EINVAL; |
346 | if (diff > skb_tailroom(e->skb)) { | 347 | if (diff > skb_tailroom(e->skb)) { |
347 | struct sk_buff *newskb; | 348 | err = pskb_expand_head(e->skb, 0, |
348 | 349 | diff - skb_tailroom(e->skb), | |
349 | newskb = skb_copy_expand(e->skb, | 350 | GFP_ATOMIC); |
350 | skb_headroom(e->skb), | 351 | if (err) { |
351 | diff, | ||
352 | GFP_ATOMIC); | ||
353 | if (newskb == NULL) { | ||
354 | printk(KERN_WARNING "ip6_queue: OOM " | 352 | printk(KERN_WARNING "ip6_queue: OOM " |
355 | "in mangle, dropping packet\n"); | 353 | "in mangle, dropping packet\n"); |
356 | return -ENOMEM; | 354 | return err; |
357 | } | 355 | } |
358 | if (e->skb->sk) | ||
359 | skb_set_owner_w(newskb, e->skb->sk); | ||
360 | kfree_skb(e->skb); | ||
361 | e->skb = newskb; | ||
362 | } | 356 | } |
363 | skb_put(e->skb, diff); | 357 | skb_put(e->skb, diff); |
364 | } | 358 | } |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 6ba98acdd7a2..3ceeffcf6f9d 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -617,6 +617,7 @@ static int | |||
617 | nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) | 617 | nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) |
618 | { | 618 | { |
619 | int diff; | 619 | int diff; |
620 | int err; | ||
620 | 621 | ||
621 | diff = data_len - e->skb->len; | 622 | diff = data_len - e->skb->len; |
622 | if (diff < 0) { | 623 | if (diff < 0) { |
@@ -626,21 +627,14 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) | |||
626 | if (data_len > 0xFFFF) | 627 | if (data_len > 0xFFFF) |
627 | return -EINVAL; | 628 | return -EINVAL; |
628 | if (diff > skb_tailroom(e->skb)) { | 629 | if (diff > skb_tailroom(e->skb)) { |
629 | struct sk_buff *newskb; | 630 | err = pskb_expand_head(e->skb, 0, |
630 | 631 | diff - skb_tailroom(e->skb), | |
631 | newskb = skb_copy_expand(e->skb, | 632 | GFP_ATOMIC); |
632 | skb_headroom(e->skb), | 633 | if (err) { |
633 | diff, | ||
634 | GFP_ATOMIC); | ||
635 | if (newskb == NULL) { | ||
636 | printk(KERN_WARNING "nf_queue: OOM " | 634 | printk(KERN_WARNING "nf_queue: OOM " |
637 | "in mangle, dropping packet\n"); | 635 | "in mangle, dropping packet\n"); |
638 | return -ENOMEM; | 636 | return err; |
639 | } | 637 | } |
640 | if (e->skb->sk) | ||
641 | skb_set_owner_w(newskb, e->skb->sk); | ||
642 | kfree_skb(e->skb); | ||
643 | e->skb = newskb; | ||
644 | } | 638 | } |
645 | skb_put(e->skb, diff); | 639 | skb_put(e->skb, diff); |
646 | } | 640 | } |
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 31b6f9d09822..f111edf5f775 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c | |||
@@ -105,14 +105,10 @@ tcpmss_mangle_packet(struct sk_buff **pskb, | |||
105 | * MSS Option not found ?! add it.. | 105 | * MSS Option not found ?! add it.. |
106 | */ | 106 | */ |
107 | if (skb_tailroom((*pskb)) < TCPOLEN_MSS) { | 107 | if (skb_tailroom((*pskb)) < TCPOLEN_MSS) { |
108 | struct sk_buff *newskb; | 108 | if (pskb_expand_head(*pskb, 0, |
109 | 109 | TCPOLEN_MSS - skb_tailroom(*pskb), | |
110 | newskb = skb_copy_expand(*pskb, skb_headroom(*pskb), | 110 | GFP_ATOMIC)) |
111 | TCPOLEN_MSS, GFP_ATOMIC); | ||
112 | if (!newskb) | ||
113 | return -1; | 111 | return -1; |
114 | kfree_skb(*pskb); | ||
115 | *pskb = newskb; | ||
116 | tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff); | 112 | tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff); |
117 | } | 113 | } |
118 | 114 | ||