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.c78
1 files changed, 33 insertions, 45 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index c196d749daf2..6537a408a4fb 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -193,7 +193,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
193 } 193 }
194 194
195 rcu_read_lock_bh(); 195 rcu_read_lock_bh();
196 nexthop = rt->rt_gateway ? rt->rt_gateway : ip_hdr(skb)->daddr; 196 nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr);
197 neigh = __ipv4_neigh_lookup_noref(dev, nexthop); 197 neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
198 if (unlikely(!neigh)) 198 if (unlikely(!neigh))
199 neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); 199 neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
@@ -371,7 +371,7 @@ int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl)
371 skb_dst_set_noref(skb, &rt->dst); 371 skb_dst_set_noref(skb, &rt->dst);
372 372
373packet_routed: 373packet_routed:
374 if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_gateway) 374 if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_uses_gateway)
375 goto no_route; 375 goto no_route;
376 376
377 /* OK, we know where to send it, allocate and build IP header. */ 377 /* OK, we know where to send it, allocate and build IP header. */
@@ -467,7 +467,9 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
467 467
468 iph = ip_hdr(skb); 468 iph = ip_hdr(skb);
469 469
470 if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) { 470 if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->local_df) ||
471 (IPCB(skb)->frag_max_size &&
472 IPCB(skb)->frag_max_size > dst_mtu(&rt->dst)))) {
471 IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS); 473 IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
472 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, 474 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
473 htonl(ip_skb_dst_mtu(skb))); 475 htonl(ip_skb_dst_mtu(skb)));
@@ -791,6 +793,7 @@ static int __ip_append_data(struct sock *sk,
791 struct flowi4 *fl4, 793 struct flowi4 *fl4,
792 struct sk_buff_head *queue, 794 struct sk_buff_head *queue,
793 struct inet_cork *cork, 795 struct inet_cork *cork,
796 struct page_frag *pfrag,
794 int getfrag(void *from, char *to, int offset, 797 int getfrag(void *from, char *to, int offset,
795 int len, int odd, struct sk_buff *skb), 798 int len, int odd, struct sk_buff *skb),
796 void *from, int length, int transhdrlen, 799 void *from, int length, int transhdrlen,
@@ -985,47 +988,30 @@ alloc_new_skb:
985 } 988 }
986 } else { 989 } else {
987 int i = skb_shinfo(skb)->nr_frags; 990 int i = skb_shinfo(skb)->nr_frags;
988 skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
989 struct page *page = cork->page;
990 int off = cork->off;
991 unsigned int left;
992
993 if (page && (left = PAGE_SIZE - off) > 0) {
994 if (copy >= left)
995 copy = left;
996 if (page != skb_frag_page(frag)) {
997 if (i == MAX_SKB_FRAGS) {
998 err = -EMSGSIZE;
999 goto error;
1000 }
1001 skb_fill_page_desc(skb, i, page, off, 0);
1002 skb_frag_ref(skb, i);
1003 frag = &skb_shinfo(skb)->frags[i];
1004 }
1005 } else if (i < MAX_SKB_FRAGS) {
1006 if (copy > PAGE_SIZE)
1007 copy = PAGE_SIZE;
1008 page = alloc_pages(sk->sk_allocation, 0);
1009 if (page == NULL) {
1010 err = -ENOMEM;
1011 goto error;
1012 }
1013 cork->page = page;
1014 cork->off = 0;
1015 991
1016 skb_fill_page_desc(skb, i, page, 0, 0); 992 err = -ENOMEM;
1017 frag = &skb_shinfo(skb)->frags[i]; 993 if (!sk_page_frag_refill(sk, pfrag))
1018 } else {
1019 err = -EMSGSIZE;
1020 goto error;
1021 }
1022 if (getfrag(from, skb_frag_address(frag)+skb_frag_size(frag),
1023 offset, copy, skb->len, skb) < 0) {
1024 err = -EFAULT;
1025 goto error; 994 goto error;
995
996 if (!skb_can_coalesce(skb, i, pfrag->page,
997 pfrag->offset)) {
998 err = -EMSGSIZE;
999 if (i == MAX_SKB_FRAGS)
1000 goto error;
1001
1002 __skb_fill_page_desc(skb, i, pfrag->page,
1003 pfrag->offset, 0);
1004 skb_shinfo(skb)->nr_frags = ++i;
1005 get_page(pfrag->page);
1026 } 1006 }
1027 cork->off += copy; 1007 copy = min_t(int, copy, pfrag->size - pfrag->offset);
1028 skb_frag_size_add(frag, copy); 1008 if (getfrag(from,
1009 page_address(pfrag->page) + pfrag->offset,
1010 offset, copy, skb->len, skb) < 0)
1011 goto error_efault;
1012
1013 pfrag->offset += copy;
1014 skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
1029 skb->len += copy; 1015 skb->len += copy;
1030 skb->data_len += copy; 1016 skb->data_len += copy;
1031 skb->truesize += copy; 1017 skb->truesize += copy;
@@ -1037,6 +1023,8 @@ alloc_new_skb:
1037 1023
1038 return 0; 1024 return 0;
1039 1025
1026error_efault:
1027 err = -EFAULT;
1040error: 1028error:
1041 cork->length -= length; 1029 cork->length -= length;
1042 IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); 1030 IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS);
@@ -1077,8 +1065,6 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
1077 cork->dst = &rt->dst; 1065 cork->dst = &rt->dst;
1078 cork->length = 0; 1066 cork->length = 0;
1079 cork->tx_flags = ipc->tx_flags; 1067 cork->tx_flags = ipc->tx_flags;
1080 cork->page = NULL;
1081 cork->off = 0;
1082 1068
1083 return 0; 1069 return 0;
1084} 1070}
@@ -1115,7 +1101,8 @@ int ip_append_data(struct sock *sk, struct flowi4 *fl4,
1115 transhdrlen = 0; 1101 transhdrlen = 0;
1116 } 1102 }
1117 1103
1118 return __ip_append_data(sk, fl4, &sk->sk_write_queue, &inet->cork.base, getfrag, 1104 return __ip_append_data(sk, fl4, &sk->sk_write_queue, &inet->cork.base,
1105 sk_page_frag(sk), getfrag,
1119 from, length, transhdrlen, flags); 1106 from, length, transhdrlen, flags);
1120} 1107}
1121 1108
@@ -1437,7 +1424,8 @@ struct sk_buff *ip_make_skb(struct sock *sk,
1437 if (err) 1424 if (err)
1438 return ERR_PTR(err); 1425 return ERR_PTR(err);
1439 1426
1440 err = __ip_append_data(sk, fl4, &queue, &cork, getfrag, 1427 err = __ip_append_data(sk, fl4, &queue, &cork,
1428 &current->task_frag, getfrag,
1441 from, length, transhdrlen, flags); 1429 from, length, transhdrlen, flags);
1442 if (err) { 1430 if (err) {
1443 __ip_flush_pending_frames(sk, &queue, &cork); 1431 __ip_flush_pending_frames(sk, &queue, &cork);