diff options
Diffstat (limited to 'net/ipv4/ip_output.c')
-rw-r--r-- | net/ipv4/ip_output.c | 78 |
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 | ||
373 | packet_routed: | 373 | packet_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 | ||
1026 | error_efault: | ||
1027 | err = -EFAULT; | ||
1040 | error: | 1028 | error: |
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 | ¤t->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); |