aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-01-11 22:14:00 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:53:47 -0500
commitc439cb2e4b13cf1cb2abcd006b906315a3381323 (patch)
tree7bb9d27214e010d37d6a715d0533a7148a8f429a /net
parent227620e295090629fcb2c46ad3828222ab65438d (diff)
[IPV4]: Add ip_local_out
Most callers of the LOCAL_OUT chain will set the IP packet length and header checksum before doing so. They also share the same output function dst_output. This patch creates a new function called ip_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 once the same thing is done for IPv6. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/igmp.c12
-rw-r--r--net/ipv4/ip_output.c39
-rw-r--r--net/ipv4/ipvs/ip_vs_xmit.c6
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c8
-rw-r--r--net/ipv4/xfrm4_output.c8
5 files changed, 31 insertions, 42 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 701558564e9..c560a9392b1 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -349,17 +349,12 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
349 349
350static int igmpv3_sendpack(struct sk_buff *skb) 350static int igmpv3_sendpack(struct sk_buff *skb)
351{ 351{
352 struct iphdr *pip = ip_hdr(skb);
353 struct igmphdr *pig = igmp_hdr(skb); 352 struct igmphdr *pig = igmp_hdr(skb);
354 const int iplen = skb->tail - skb->network_header;
355 const int igmplen = skb->tail - skb->transport_header; 353 const int igmplen = skb->tail - skb->transport_header;
356 354
357 pip->tot_len = htons(iplen);
358 ip_send_check(pip);
359 pig->csum = ip_compute_csum(igmp_hdr(skb), igmplen); 355 pig->csum = ip_compute_csum(igmp_hdr(skb), igmplen);
360 356
361 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dev, 357 return ip_local_out(skb);
362 dst_output);
363} 358}
364 359
365static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel) 360static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel)
@@ -680,13 +675,11 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
680 iph->daddr = dst; 675 iph->daddr = dst;
681 iph->saddr = rt->rt_src; 676 iph->saddr = rt->rt_src;
682 iph->protocol = IPPROTO_IGMP; 677 iph->protocol = IPPROTO_IGMP;
683 iph->tot_len = htons(IGMP_SIZE);
684 ip_select_ident(iph, &rt->u.dst, NULL); 678 ip_select_ident(iph, &rt->u.dst, NULL);
685 ((u8*)&iph[1])[0] = IPOPT_RA; 679 ((u8*)&iph[1])[0] = IPOPT_RA;
686 ((u8*)&iph[1])[1] = 4; 680 ((u8*)&iph[1])[1] = 4;
687 ((u8*)&iph[1])[2] = 0; 681 ((u8*)&iph[1])[2] = 0;
688 ((u8*)&iph[1])[3] = 0; 682 ((u8*)&iph[1])[3] = 0;
689 ip_send_check(iph);
690 683
691 ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr)); 684 ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
692 ih->type=type; 685 ih->type=type;
@@ -695,8 +688,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
695 ih->group=group; 688 ih->group=group;
696 ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr)); 689 ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
697 690
698 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, 691 return ip_local_out(skb);
699 dst_output);
700} 692}
701 693
702static void igmp_gq_timer_expire(unsigned long data) 694static void igmp_gq_timer_expire(unsigned long data)
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index bc9e57550e8..03b9b060027 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -91,6 +91,28 @@ __inline__ void ip_send_check(struct iphdr *iph)
91 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 91 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
92} 92}
93 93
94int __ip_local_out(struct sk_buff *skb)
95{
96 struct iphdr *iph = ip_hdr(skb);
97
98 iph->tot_len = htons(skb->len);
99 ip_send_check(iph);
100 return nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev,
101 dst_output);
102}
103
104int ip_local_out(struct sk_buff *skb)
105{
106 int err;
107
108 err = __ip_local_out(skb);
109 if (likely(err == 1))
110 err = dst_output(skb);
111
112 return err;
113}
114EXPORT_SYMBOL_GPL(ip_local_out);
115
94/* dev_loopback_xmit for use with netfilter. */ 116/* dev_loopback_xmit for use with netfilter. */
95static int ip_dev_loopback_xmit(struct sk_buff *newskb) 117static int ip_dev_loopback_xmit(struct sk_buff *newskb)
96{ 118{
@@ -138,20 +160,17 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
138 iph->daddr = rt->rt_dst; 160 iph->daddr = rt->rt_dst;
139 iph->saddr = rt->rt_src; 161 iph->saddr = rt->rt_src;
140 iph->protocol = sk->sk_protocol; 162 iph->protocol = sk->sk_protocol;
141 iph->tot_len = htons(skb->len);
142 ip_select_ident(iph, &rt->u.dst, sk); 163 ip_select_ident(iph, &rt->u.dst, sk);
143 164
144 if (opt && opt->optlen) { 165 if (opt && opt->optlen) {
145 iph->ihl += opt->optlen>>2; 166 iph->ihl += opt->optlen>>2;
146 ip_options_build(skb, opt, daddr, rt, 0); 167 ip_options_build(skb, opt, daddr, rt, 0);
147 } 168 }
148 ip_send_check(iph);
149 169
150 skb->priority = sk->sk_priority; 170 skb->priority = sk->sk_priority;
151 171
152 /* Send it out. */ 172 /* Send it out. */
153 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, 173 return ip_local_out(skb);
154 dst_output);
155} 174}
156 175
157EXPORT_SYMBOL_GPL(ip_build_and_send_pkt); 176EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
@@ -347,7 +366,6 @@ packet_routed:
347 skb_reset_network_header(skb); 366 skb_reset_network_header(skb);
348 iph = ip_hdr(skb); 367 iph = ip_hdr(skb);
349 *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); 368 *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
350 iph->tot_len = htons(skb->len);
351 if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok) 369 if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
352 iph->frag_off = htons(IP_DF); 370 iph->frag_off = htons(IP_DF);
353 else 371 else
@@ -366,13 +384,9 @@ packet_routed:
366 ip_select_ident_more(iph, &rt->u.dst, sk, 384 ip_select_ident_more(iph, &rt->u.dst, sk,
367 (skb_shinfo(skb)->gso_segs ?: 1) - 1); 385 (skb_shinfo(skb)->gso_segs ?: 1) - 1);
368 386
369 /* Add an IP checksum. */
370 ip_send_check(iph);
371
372 skb->priority = sk->sk_priority; 387 skb->priority = sk->sk_priority;
373 388
374 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, 389 return ip_local_out(skb);
375 dst_output);
376 390
377no_route: 391no_route:
378 IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES); 392 IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
@@ -1262,14 +1276,12 @@ int ip_push_pending_frames(struct sock *sk)
1262 ip_options_build(skb, opt, inet->cork.addr, rt, 0); 1276 ip_options_build(skb, opt, inet->cork.addr, rt, 0);
1263 } 1277 }
1264 iph->tos = inet->tos; 1278 iph->tos = inet->tos;
1265 iph->tot_len = htons(skb->len);
1266 iph->frag_off = df; 1279 iph->frag_off = df;
1267 ip_select_ident(iph, &rt->u.dst, sk); 1280 ip_select_ident(iph, &rt->u.dst, sk);
1268 iph->ttl = ttl; 1281 iph->ttl = ttl;
1269 iph->protocol = sk->sk_protocol; 1282 iph->protocol = sk->sk_protocol;
1270 iph->saddr = rt->rt_src; 1283 iph->saddr = rt->rt_src;
1271 iph->daddr = rt->rt_dst; 1284 iph->daddr = rt->rt_dst;
1272 ip_send_check(iph);
1273 1285
1274 skb->priority = sk->sk_priority; 1286 skb->priority = sk->sk_priority;
1275 skb->dst = dst_clone(&rt->u.dst); 1287 skb->dst = dst_clone(&rt->u.dst);
@@ -1279,8 +1291,7 @@ int ip_push_pending_frames(struct sock *sk)
1279 skb_transport_header(skb))->type); 1291 skb_transport_header(skb))->type);
1280 1292
1281 /* Netfilter gets whole the not fragmented skb. */ 1293 /* Netfilter gets whole the not fragmented skb. */
1282 err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, 1294 err = ip_local_out(skb);
1283 skb->dst->dev, dst_output);
1284 if (err) { 1295 if (err) {
1285 if (err > 0) 1296 if (err > 0)
1286 err = inet->recverr ? net_xmit_errno(err) : 0; 1297 err = inet->recverr ? net_xmit_errno(err) : 0;
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index 7c074e386c1..66775ad9e32 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -16,8 +16,8 @@
16 */ 16 */
17 17
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/ip.h>
20#include <linux/tcp.h> /* for tcphdr */ 19#include <linux/tcp.h> /* for tcphdr */
20#include <net/ip.h>
21#include <net/tcp.h> /* for csum_tcpudp_magic */ 21#include <net/tcp.h> /* for csum_tcpudp_magic */
22#include <net/udp.h> 22#include <net/udp.h>
23#include <net/icmp.h> /* for icmp_send */ 23#include <net/icmp.h> /* for icmp_send */
@@ -406,14 +406,12 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
406 iph->daddr = rt->rt_dst; 406 iph->daddr = rt->rt_dst;
407 iph->saddr = rt->rt_src; 407 iph->saddr = rt->rt_src;
408 iph->ttl = old_iph->ttl; 408 iph->ttl = old_iph->ttl;
409 iph->tot_len = htons(skb->len);
410 ip_select_ident(iph, &rt->u.dst, NULL); 409 ip_select_ident(iph, &rt->u.dst, NULL);
411 ip_send_check(iph);
412 410
413 /* Another hack: avoid icmp_send in ip_fragment */ 411 /* Another hack: avoid icmp_send in ip_fragment */
414 skb->local_df = 1; 412 skb->local_df = 1;
415 413
416 IP_VS_XMIT(skb, rt); 414 ip_local_out(skb);
417 415
418 LeaveFunction(10); 416 LeaveFunction(10);
419 417
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index dcf4d21d511..ccb2a03dcd5 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -90,7 +90,6 @@ static void send_reset(struct sk_buff *oldskb, int hook)
90 /* Truncate to length (no data) */ 90 /* Truncate to length (no data) */
91 tcph->doff = sizeof(struct tcphdr)/4; 91 tcph->doff = sizeof(struct tcphdr)/4;
92 skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr)); 92 skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
93 niph->tot_len = htons(nskb->len);
94 93
95 if (tcph->ack) { 94 if (tcph->ack) {
96 needs_ack = 0; 95 needs_ack = 0;
@@ -139,18 +138,13 @@ static void send_reset(struct sk_buff *oldskb, int hook)
139 /* Adjust IP TTL */ 138 /* Adjust IP TTL */
140 niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); 139 niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
141 140
142 /* Adjust IP checksum */
143 niph->check = 0;
144 niph->check = ip_fast_csum(skb_network_header(nskb), niph->ihl);
145
146 /* "Never happens" */ 141 /* "Never happens" */
147 if (nskb->len > dst_mtu(nskb->dst)) 142 if (nskb->len > dst_mtu(nskb->dst))
148 goto free_nskb; 143 goto free_nskb;
149 144
150 nf_ct_attach(nskb, oldskb); 145 nf_ct_attach(nskb, oldskb);
151 146
152 NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, 147 ip_local_out(nskb);
153 dst_output);
154 return; 148 return;
155 149
156 free_nskb: 150 free_nskb:
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 13fd11335e2..0ffc3d07848 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -69,17 +69,12 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
69 69
70static inline int xfrm4_output_one(struct sk_buff *skb) 70static inline int xfrm4_output_one(struct sk_buff *skb)
71{ 71{
72 struct iphdr *iph;
73 int err; 72 int err;
74 73
75 err = xfrm_output(skb); 74 err = xfrm_output(skb);
76 if (err) 75 if (err)
77 goto error_nolock; 76 goto error_nolock;
78 77
79 iph = ip_hdr(skb);
80 iph->tot_len = htons(skb->len);
81 ip_send_check(iph);
82
83 IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; 78 IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
84 err = 0; 79 err = 0;
85 80
@@ -97,8 +92,7 @@ static int xfrm4_output_finish2(struct sk_buff *skb)
97 while (likely((err = xfrm4_output_one(skb)) == 0)) { 92 while (likely((err = xfrm4_output_one(skb)) == 0)) {
98 nf_reset(skb); 93 nf_reset(skb);
99 94
100 err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, 95 err = __ip_local_out(skb);
101 skb->dst->dev, dst_output);
102 if (unlikely(err != 1)) 96 if (unlikely(err != 1))
103 break; 97 break;
104 98