aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-01-11 22:15:08 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:53:47 -0500
commitef76bc23ef2acf20c8f7f841a542d8ab74c827c6 (patch)
tree11ae8004f4c25ac91339f13a86fdd9f170faeb2e
parentc439cb2e4b13cf1cb2abcd006b906315a3381323 (diff)
[IPV6]: Add ip6_local_out
Most callers of the LOCAL_OUT chain will set the IP packet length before doing so. They also share the same output function dst_output. This patch creates a new function called ip6_local_out which does all of that and converts the appropriate users over to it. Apart from removing duplicate code, it will also help in merging the IPsec output path. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/ipv6.h3
-rw-r--r--net/ipv6/ip6_output.c33
-rw-r--r--net/ipv6/ip6_tunnel.c4
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c4
-rw-r--r--net/ipv6/xfrm6_output.c7
5 files changed, 33 insertions, 18 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index ae328b680ff2..e90f9625cb1b 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -509,6 +509,9 @@ extern int ip6_forward(struct sk_buff *skb);
509extern int ip6_input(struct sk_buff *skb); 509extern int ip6_input(struct sk_buff *skb);
510extern int ip6_mc_input(struct sk_buff *skb); 510extern int ip6_mc_input(struct sk_buff *skb);
511 511
512extern int __ip6_local_out(struct sk_buff *skb);
513extern int ip6_local_out(struct sk_buff *skb);
514
512/* 515/*
513 * Extension header (options) processing 516 * Extension header (options) processing
514 */ 517 */
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 387030d2483c..bd121f9ae0a7 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -29,7 +29,7 @@
29 */ 29 */
30 30
31#include <linux/errno.h> 31#include <linux/errno.h>
32#include <linux/types.h> 32#include <linux/kernel.h>
33#include <linux/string.h> 33#include <linux/string.h>
34#include <linux/socket.h> 34#include <linux/socket.h>
35#include <linux/net.h> 35#include <linux/net.h>
@@ -70,6 +70,31 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f
70 spin_unlock_bh(&ip6_id_lock); 70 spin_unlock_bh(&ip6_id_lock);
71} 71}
72 72
73int __ip6_local_out(struct sk_buff *skb)
74{
75 int len;
76
77 len = skb->len - sizeof(struct ipv6hdr);
78 if (len > IPV6_MAXPLEN)
79 len = 0;
80 ipv6_hdr(skb)->payload_len = htons(len);
81
82 return nf_hook(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev,
83 dst_output);
84}
85
86int ip6_local_out(struct sk_buff *skb)
87{
88 int err;
89
90 err = __ip6_local_out(skb);
91 if (likely(err == 1))
92 err = dst_output(skb);
93
94 return err;
95}
96EXPORT_SYMBOL_GPL(ip6_local_out);
97
73static int ip6_output_finish(struct sk_buff *skb) 98static int ip6_output_finish(struct sk_buff *skb)
74{ 99{
75 struct dst_entry *dst = skb->dst; 100 struct dst_entry *dst = skb->dst;
@@ -1403,10 +1428,6 @@ int ip6_push_pending_frames(struct sock *sk)
1403 *(__be32*)hdr = fl->fl6_flowlabel | 1428 *(__be32*)hdr = fl->fl6_flowlabel |
1404 htonl(0x60000000 | ((int)np->cork.tclass << 20)); 1429 htonl(0x60000000 | ((int)np->cork.tclass << 20));
1405 1430
1406 if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN)
1407 hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
1408 else
1409 hdr->payload_len = 0;
1410 hdr->hop_limit = np->cork.hop_limit; 1431 hdr->hop_limit = np->cork.hop_limit;
1411 hdr->nexthdr = proto; 1432 hdr->nexthdr = proto;
1412 ipv6_addr_copy(&hdr->saddr, &fl->fl6_src); 1433 ipv6_addr_copy(&hdr->saddr, &fl->fl6_src);
@@ -1423,7 +1444,7 @@ int ip6_push_pending_frames(struct sock *sk)
1423 ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); 1444 ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
1424 } 1445 }
1425 1446
1426 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); 1447 err = ip6_local_out(skb);
1427 if (err) { 1448 if (err) {
1428 if (err > 0) 1449 if (err > 0)
1429 err = np->recverr ? net_xmit_errno(err) : 0; 1450 err = np->recverr ? net_xmit_errno(err) : 0;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index a4051afaf776..29b5321e39c3 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -910,15 +910,13 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
910 *(__be32*)ipv6h = fl->fl6_flowlabel | htonl(0x60000000); 910 *(__be32*)ipv6h = fl->fl6_flowlabel | htonl(0x60000000);
911 dsfield = INET_ECN_encapsulate(0, dsfield); 911 dsfield = INET_ECN_encapsulate(0, dsfield);
912 ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield); 912 ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
913 ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
914 ipv6h->hop_limit = t->parms.hop_limit; 913 ipv6h->hop_limit = t->parms.hop_limit;
915 ipv6h->nexthdr = proto; 914 ipv6h->nexthdr = proto;
916 ipv6_addr_copy(&ipv6h->saddr, &fl->fl6_src); 915 ipv6_addr_copy(&ipv6h->saddr, &fl->fl6_src);
917 ipv6_addr_copy(&ipv6h->daddr, &fl->fl6_dst); 916 ipv6_addr_copy(&ipv6h->daddr, &fl->fl6_dst);
918 nf_reset(skb); 917 nf_reset(skb);
919 pkt_len = skb->len; 918 pkt_len = skb->len;
920 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, 919 err = ip6_local_out(skb);
921 skb->dst->dev, dst_output);
922 920
923 if (net_xmit_eval(err) == 0) { 921 if (net_xmit_eval(err) == 0) {
924 stats->tx_bytes += pkt_len; 922 stats->tx_bytes += pkt_len;
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 1a7d2917545d..c1c663482837 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -121,7 +121,6 @@ static void send_reset(struct sk_buff *oldskb)
121 ip6h->version = 6; 121 ip6h->version = 6;
122 ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT); 122 ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
123 ip6h->nexthdr = IPPROTO_TCP; 123 ip6h->nexthdr = IPPROTO_TCP;
124 ip6h->payload_len = htons(sizeof(struct tcphdr));
125 ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr); 124 ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
126 ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr); 125 ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
127 126
@@ -159,8 +158,7 @@ static void send_reset(struct sk_buff *oldskb)
159 158
160 nf_ct_attach(nskb, oldskb); 159 nf_ct_attach(nskb, oldskb);
161 160
162 NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev, 161 ip6_local_out(nskb);
163 dst_output);
164} 162}
165 163
166static inline void 164static inline void
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index c45050cfe72b..0f0ff51f6dba 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -75,16 +75,12 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
75 75
76static inline int xfrm6_output_one(struct sk_buff *skb) 76static inline int xfrm6_output_one(struct sk_buff *skb)
77{ 77{
78 struct ipv6hdr *iph;
79 int err; 78 int err;
80 79
81 err = xfrm_output(skb); 80 err = xfrm_output(skb);
82 if (err) 81 if (err)
83 goto error_nolock; 82 goto error_nolock;
84 83
85 iph = ipv6_hdr(skb);
86 iph->payload_len = htons(skb->len - sizeof(*iph));
87
88 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; 84 IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
89 err = 0; 85 err = 0;
90 86
@@ -102,8 +98,7 @@ static int xfrm6_output_finish2(struct sk_buff *skb)
102 while (likely((err = xfrm6_output_one(skb)) == 0)) { 98 while (likely((err = xfrm6_output_one(skb)) == 0)) {
103 nf_reset(skb); 99 nf_reset(skb);
104 100
105 err = nf_hook(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, 101 err = __ip6_local_out(skb);
106 skb->dst->dev, dst_output);
107 if (unlikely(err != 1)) 102 if (unlikely(err != 1))
108 break; 103 break;
109 104