aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_output.c')
-rw-r--r--net/ipv4/ip_output.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index d2a8f8bb78a6..8ebe86dd72af 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -430,7 +430,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
430 * single device frame, and queue such a frame for sending. 430 * single device frame, and queue such a frame for sending.
431 */ 431 */
432 432
433int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) 433int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
434{ 434{
435 struct iphdr *iph; 435 struct iphdr *iph;
436 int raw = 0; 436 int raw = 0;
@@ -720,7 +720,7 @@ static inline int ip_ufo_append_data(struct sock *sk,
720 int getfrag(void *from, char *to, int offset, int len, 720 int getfrag(void *from, char *to, int offset, int len,
721 int odd, struct sk_buff *skb), 721 int odd, struct sk_buff *skb),
722 void *from, int length, int hh_len, int fragheaderlen, 722 void *from, int length, int hh_len, int fragheaderlen,
723 int transhdrlen, int mtu,unsigned int flags) 723 int transhdrlen, int mtu, unsigned int flags)
724{ 724{
725 struct sk_buff *skb; 725 struct sk_buff *skb;
726 int err; 726 int err;
@@ -741,7 +741,7 @@ static inline int ip_ufo_append_data(struct sock *sk,
741 skb_reserve(skb, hh_len); 741 skb_reserve(skb, hh_len);
742 742
743 /* create space for UDP/IP header */ 743 /* create space for UDP/IP header */
744 skb_put(skb,fragheaderlen + transhdrlen); 744 skb_put(skb, fragheaderlen + transhdrlen);
745 745
746 /* initialize network header pointer */ 746 /* initialize network header pointer */
747 skb_reset_network_header(skb); 747 skb_reset_network_header(skb);
@@ -778,7 +778,7 @@ int ip_append_data(struct sock *sk,
778 int getfrag(void *from, char *to, int offset, int len, 778 int getfrag(void *from, char *to, int offset, int len,
779 int odd, struct sk_buff *skb), 779 int odd, struct sk_buff *skb),
780 void *from, int length, int transhdrlen, 780 void *from, int length, int transhdrlen,
781 struct ipcm_cookie *ipc, struct rtable *rt, 781 struct ipcm_cookie *ipc, struct rtable **rtp,
782 unsigned int flags) 782 unsigned int flags)
783{ 783{
784 struct inet_sock *inet = inet_sk(sk); 784 struct inet_sock *inet = inet_sk(sk);
@@ -793,6 +793,7 @@ int ip_append_data(struct sock *sk,
793 int offset = 0; 793 int offset = 0;
794 unsigned int maxfraglen, fragheaderlen; 794 unsigned int maxfraglen, fragheaderlen;
795 int csummode = CHECKSUM_NONE; 795 int csummode = CHECKSUM_NONE;
796 struct rtable *rt;
796 797
797 if (flags&MSG_PROBE) 798 if (flags&MSG_PROBE)
798 return 0; 799 return 0;
@@ -812,7 +813,11 @@ int ip_append_data(struct sock *sk,
812 inet->cork.flags |= IPCORK_OPT; 813 inet->cork.flags |= IPCORK_OPT;
813 inet->cork.addr = ipc->addr; 814 inet->cork.addr = ipc->addr;
814 } 815 }
815 dst_hold(&rt->u.dst); 816 rt = *rtp;
817 /*
818 * We steal reference to this route, caller should not release it
819 */
820 *rtp = NULL;
816 inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ? 821 inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ?
817 rt->u.dst.dev->mtu : 822 rt->u.dst.dev->mtu :
818 dst_mtu(rt->u.dst.path); 823 dst_mtu(rt->u.dst.path);
@@ -1279,7 +1284,12 @@ int ip_push_pending_frames(struct sock *sk)
1279 1284
1280 skb->priority = sk->sk_priority; 1285 skb->priority = sk->sk_priority;
1281 skb->mark = sk->sk_mark; 1286 skb->mark = sk->sk_mark;
1282 skb->dst = dst_clone(&rt->u.dst); 1287 /*
1288 * Steal rt from cork.dst to avoid a pair of atomic_inc/atomic_dec
1289 * on dst refcount
1290 */
1291 inet->cork.dst = NULL;
1292 skb->dst = &rt->u.dst;
1283 1293
1284 if (iph->protocol == IPPROTO_ICMP) 1294 if (iph->protocol == IPPROTO_ICMP)
1285 icmp_out_count(net, ((struct icmphdr *) 1295 icmp_out_count(net, ((struct icmphdr *)
@@ -1391,7 +1401,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
1391 sk->sk_protocol = ip_hdr(skb)->protocol; 1401 sk->sk_protocol = ip_hdr(skb)->protocol;
1392 sk->sk_bound_dev_if = arg->bound_dev_if; 1402 sk->sk_bound_dev_if = arg->bound_dev_if;
1393 ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0, 1403 ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0,
1394 &ipc, rt, MSG_DONTWAIT); 1404 &ipc, &rt, MSG_DONTWAIT);
1395 if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { 1405 if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
1396 if (arg->csumoffset >= 0) 1406 if (arg->csumoffset >= 0)
1397 *((__sum16 *)skb_transport_header(skb) + 1407 *((__sum16 *)skb_transport_header(skb) +