diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2008-01-11 22:15:08 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:53:47 -0500 |
commit | ef76bc23ef2acf20c8f7f841a542d8ab74c827c6 (patch) | |
tree | 11ae8004f4c25ac91339f13a86fdd9f170faeb2e /net/ipv6 | |
parent | c439cb2e4b13cf1cb2abcd006b906315a3381323 (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>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/ip6_output.c | 33 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 4 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_REJECT.c | 4 | ||||
-rw-r--r-- | net/ipv6/xfrm6_output.c | 7 |
4 files changed, 30 insertions, 18 deletions
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 | ||
73 | int __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 | |||
86 | int 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 | } | ||
96 | EXPORT_SYMBOL_GPL(ip6_local_out); | ||
97 | |||
73 | static int ip6_output_finish(struct sk_buff *skb) | 98 | static 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 | ||
166 | static inline void | 164 | static 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 | ||
76 | static inline int xfrm6_output_one(struct sk_buff *skb) | 76 | static 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 | ||