aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-10-14 03:39:55 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-15 15:26:28 -0400
commit2ca7b0ac022aa0158599178fe1056b1ba9ec8b97 (patch)
tree6eece25447f0ec3b5d5f5533e49e10fde4d59f35
parentaf1e1cf073e3d038b7aac417a20585ecdcab7de6 (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.c13
-rw-r--r--net/bridge/netfilter/ebt_redirect.c13
-rw-r--r--net/bridge/netfilter/ebt_snat.c13
-rw-r--r--net/ipv4/netfilter.c31
-rw-r--r--net/ipv4/netfilter/arpt_mangle.c14
-rw-r--r--net/ipv4/netfilter/ip_queue.c22
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c10
-rw-r--r--net/ipv6/netfilter/ip6_queue.c18
-rw-r--r--net/netfilter/nfnetlink_queue.c18
-rw-r--r--net/netfilter/xt_TCPMSS.c10
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}
123EXPORT_SYMBOL(ip_xfrm_me_harder); 110EXPORT_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
335ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) 335ipq_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. */
114static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) 114static 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
332ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) 332ipq_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
617nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) 617nfqnl_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