diff options
Diffstat (limited to 'net/ipv4/ip_output.c')
| -rw-r--r-- | net/ipv4/ip_output.c | 52 |
1 files changed, 27 insertions, 25 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 7624fd1d8f9f..fc195a44fc2e 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
| @@ -53,7 +53,6 @@ | |||
| 53 | #include <linux/mm.h> | 53 | #include <linux/mm.h> |
| 54 | #include <linux/string.h> | 54 | #include <linux/string.h> |
| 55 | #include <linux/errno.h> | 55 | #include <linux/errno.h> |
| 56 | #include <linux/config.h> | ||
| 57 | 56 | ||
| 58 | #include <linux/socket.h> | 57 | #include <linux/socket.h> |
| 59 | #include <linux/sockios.h> | 58 | #include <linux/sockios.h> |
| @@ -84,7 +83,7 @@ | |||
| 84 | #include <linux/netlink.h> | 83 | #include <linux/netlink.h> |
| 85 | #include <linux/tcp.h> | 84 | #include <linux/tcp.h> |
| 86 | 85 | ||
| 87 | int sysctl_ip_default_ttl = IPDEFTTL; | 86 | int sysctl_ip_default_ttl __read_mostly = IPDEFTTL; |
| 88 | 87 | ||
| 89 | /* Generate a checksum for an outgoing IP datagram. */ | 88 | /* Generate a checksum for an outgoing IP datagram. */ |
| 90 | __inline__ void ip_send_check(struct iphdr *iph) | 89 | __inline__ void ip_send_check(struct iphdr *iph) |
| @@ -119,7 +118,7 @@ static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst) | |||
| 119 | * | 118 | * |
| 120 | */ | 119 | */ |
| 121 | int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, | 120 | int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, |
| 122 | u32 saddr, u32 daddr, struct ip_options *opt) | 121 | __be32 saddr, __be32 daddr, struct ip_options *opt) |
| 123 | { | 122 | { |
| 124 | struct inet_sock *inet = inet_sk(sk); | 123 | struct inet_sock *inet = inet_sk(sk); |
| 125 | struct rtable *rt = (struct rtable *)skb->dst; | 124 | struct rtable *rt = (struct rtable *)skb->dst; |
| @@ -210,7 +209,7 @@ static inline int ip_finish_output(struct sk_buff *skb) | |||
| 210 | return dst_output(skb); | 209 | return dst_output(skb); |
| 211 | } | 210 | } |
| 212 | #endif | 211 | #endif |
| 213 | if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) | 212 | if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) |
| 214 | return ip_fragment(skb, ip_finish_output2); | 213 | return ip_fragment(skb, ip_finish_output2); |
| 215 | else | 214 | else |
| 216 | return ip_finish_output2(skb); | 215 | return ip_finish_output2(skb); |
| @@ -307,7 +306,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) | |||
| 307 | /* Make sure we can route this packet. */ | 306 | /* Make sure we can route this packet. */ |
| 308 | rt = (struct rtable *)__sk_dst_check(sk, 0); | 307 | rt = (struct rtable *)__sk_dst_check(sk, 0); |
| 309 | if (rt == NULL) { | 308 | if (rt == NULL) { |
| 310 | u32 daddr; | 309 | __be32 daddr; |
| 311 | 310 | ||
| 312 | /* Use correct destination address if we have options. */ | 311 | /* Use correct destination address if we have options. */ |
| 313 | daddr = inet->daddr; | 312 | daddr = inet->daddr; |
| @@ -329,6 +328,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) | |||
| 329 | * keep trying until route appears or the connection times | 328 | * keep trying until route appears or the connection times |
| 330 | * itself out. | 329 | * itself out. |
| 331 | */ | 330 | */ |
| 331 | security_sk_classify_flow(sk, &fl); | ||
| 332 | if (ip_route_output_flow(&rt, &fl, sk, 0)) | 332 | if (ip_route_output_flow(&rt, &fl, sk, 0)) |
| 333 | goto no_route; | 333 | goto no_route; |
| 334 | } | 334 | } |
| @@ -426,7 +426,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) | |||
| 426 | int ptr; | 426 | int ptr; |
| 427 | struct net_device *dev; | 427 | struct net_device *dev; |
| 428 | struct sk_buff *skb2; | 428 | struct sk_buff *skb2; |
| 429 | unsigned int mtu, hlen, left, len, ll_rs; | 429 | unsigned int mtu, hlen, left, len, ll_rs, pad; |
| 430 | int offset; | 430 | int offset; |
| 431 | __be16 not_last_frag; | 431 | __be16 not_last_frag; |
| 432 | struct rtable *rt = (struct rtable*)skb->dst; | 432 | struct rtable *rt = (struct rtable*)skb->dst; |
| @@ -441,6 +441,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) | |||
| 441 | iph = skb->nh.iph; | 441 | iph = skb->nh.iph; |
| 442 | 442 | ||
| 443 | if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) { | 443 | if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) { |
| 444 | IP_INC_STATS(IPSTATS_MIB_FRAGFAILS); | ||
| 444 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, | 445 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, |
| 445 | htonl(dst_mtu(&rt->u.dst))); | 446 | htonl(dst_mtu(&rt->u.dst))); |
| 446 | kfree_skb(skb); | 447 | kfree_skb(skb); |
| @@ -527,6 +528,8 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) | |||
| 527 | 528 | ||
| 528 | err = output(skb); | 529 | err = output(skb); |
| 529 | 530 | ||
| 531 | if (!err) | ||
| 532 | IP_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 530 | if (err || !frag) | 533 | if (err || !frag) |
| 531 | break; | 534 | break; |
| 532 | 535 | ||
| @@ -553,14 +556,13 @@ slow_path: | |||
| 553 | left = skb->len - hlen; /* Space per frame */ | 556 | left = skb->len - hlen; /* Space per frame */ |
| 554 | ptr = raw + hlen; /* Where to start from */ | 557 | ptr = raw + hlen; /* Where to start from */ |
| 555 | 558 | ||
| 556 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
| 557 | /* for bridged IP traffic encapsulated inside f.e. a vlan header, | 559 | /* for bridged IP traffic encapsulated inside f.e. a vlan header, |
| 558 | * we need to make room for the encapsulating header */ | 560 | * we need to make room for the encapsulating header |
| 559 | ll_rs = LL_RESERVED_SPACE_EXTRA(rt->u.dst.dev, nf_bridge_pad(skb)); | 561 | */ |
| 560 | mtu -= nf_bridge_pad(skb); | 562 | pad = nf_bridge_pad(skb); |
| 561 | #else | 563 | ll_rs = LL_RESERVED_SPACE_EXTRA(rt->u.dst.dev, pad); |
| 562 | ll_rs = LL_RESERVED_SPACE(rt->u.dst.dev); | 564 | mtu -= pad; |
| 563 | #endif | 565 | |
| 564 | /* | 566 | /* |
| 565 | * Fragment the datagram. | 567 | * Fragment the datagram. |
| 566 | */ | 568 | */ |
| @@ -650,9 +652,6 @@ slow_path: | |||
| 650 | /* | 652 | /* |
| 651 | * Put this fragment into the sending queue. | 653 | * Put this fragment into the sending queue. |
| 652 | */ | 654 | */ |
| 653 | |||
| 654 | IP_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 655 | |||
| 656 | iph->tot_len = htons(len + hlen); | 655 | iph->tot_len = htons(len + hlen); |
| 657 | 656 | ||
| 658 | ip_send_check(iph); | 657 | ip_send_check(iph); |
| @@ -660,6 +659,8 @@ slow_path: | |||
| 660 | err = output(skb2); | 659 | err = output(skb2); |
| 661 | if (err) | 660 | if (err) |
| 662 | goto fail; | 661 | goto fail; |
| 662 | |||
| 663 | IP_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 663 | } | 664 | } |
| 664 | kfree_skb(skb); | 665 | kfree_skb(skb); |
| 665 | IP_INC_STATS(IPSTATS_MIB_FRAGOKS); | 666 | IP_INC_STATS(IPSTATS_MIB_FRAGOKS); |
| @@ -678,7 +679,7 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk | |||
| 678 | { | 679 | { |
| 679 | struct iovec *iov = from; | 680 | struct iovec *iov = from; |
| 680 | 681 | ||
| 681 | if (skb->ip_summed == CHECKSUM_HW) { | 682 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
| 682 | if (memcpy_fromiovecend(to, iov, offset, len) < 0) | 683 | if (memcpy_fromiovecend(to, iov, offset, len) < 0) |
| 683 | return -EFAULT; | 684 | return -EFAULT; |
| 684 | } else { | 685 | } else { |
| @@ -734,7 +735,7 @@ static inline int ip_ufo_append_data(struct sock *sk, | |||
| 734 | /* initialize protocol header pointer */ | 735 | /* initialize protocol header pointer */ |
| 735 | skb->h.raw = skb->data + fragheaderlen; | 736 | skb->h.raw = skb->data + fragheaderlen; |
| 736 | 737 | ||
| 737 | skb->ip_summed = CHECKSUM_HW; | 738 | skb->ip_summed = CHECKSUM_PARTIAL; |
| 738 | skb->csum = 0; | 739 | skb->csum = 0; |
| 739 | sk->sk_sndmsg_off = 0; | 740 | sk->sk_sndmsg_off = 0; |
| 740 | } | 741 | } |
| @@ -744,7 +745,7 @@ static inline int ip_ufo_append_data(struct sock *sk, | |||
| 744 | if (!err) { | 745 | if (!err) { |
| 745 | /* specify the length of each IP datagram fragment*/ | 746 | /* specify the length of each IP datagram fragment*/ |
| 746 | skb_shinfo(skb)->gso_size = mtu - fragheaderlen; | 747 | skb_shinfo(skb)->gso_size = mtu - fragheaderlen; |
| 747 | skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; | 748 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; |
| 748 | __skb_queue_tail(&sk->sk_write_queue, skb); | 749 | __skb_queue_tail(&sk->sk_write_queue, skb); |
| 749 | 750 | ||
| 750 | return 0; | 751 | return 0; |
| @@ -842,7 +843,7 @@ int ip_append_data(struct sock *sk, | |||
| 842 | length + fragheaderlen <= mtu && | 843 | length + fragheaderlen <= mtu && |
| 843 | rt->u.dst.dev->features & NETIF_F_ALL_CSUM && | 844 | rt->u.dst.dev->features & NETIF_F_ALL_CSUM && |
| 844 | !exthdrlen) | 845 | !exthdrlen) |
| 845 | csummode = CHECKSUM_HW; | 846 | csummode = CHECKSUM_PARTIAL; |
| 846 | 847 | ||
| 847 | inet->cork.length += length; | 848 | inet->cork.length += length; |
| 848 | if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && | 849 | if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) && |
| @@ -947,7 +948,7 @@ alloc_new_skb: | |||
| 947 | skb_prev->csum = csum_sub(skb_prev->csum, | 948 | skb_prev->csum = csum_sub(skb_prev->csum, |
| 948 | skb->csum); | 949 | skb->csum); |
| 949 | data += fraggap; | 950 | data += fraggap; |
| 950 | skb_trim(skb_prev, maxfraglen); | 951 | pskb_trim_unique(skb_prev, maxfraglen); |
| 951 | } | 952 | } |
| 952 | 953 | ||
| 953 | copy = datalen - transhdrlen - fraggap; | 954 | copy = datalen - transhdrlen - fraggap; |
| @@ -1089,14 +1090,14 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, | |||
| 1089 | if ((sk->sk_protocol == IPPROTO_UDP) && | 1090 | if ((sk->sk_protocol == IPPROTO_UDP) && |
| 1090 | (rt->u.dst.dev->features & NETIF_F_UFO)) { | 1091 | (rt->u.dst.dev->features & NETIF_F_UFO)) { |
| 1091 | skb_shinfo(skb)->gso_size = mtu - fragheaderlen; | 1092 | skb_shinfo(skb)->gso_size = mtu - fragheaderlen; |
| 1092 | skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4; | 1093 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; |
| 1093 | } | 1094 | } |
| 1094 | 1095 | ||
| 1095 | 1096 | ||
| 1096 | while (size > 0) { | 1097 | while (size > 0) { |
| 1097 | int i; | 1098 | int i; |
| 1098 | 1099 | ||
| 1099 | if (skb_shinfo(skb)->gso_size) | 1100 | if (skb_is_gso(skb)) |
| 1100 | len = size; | 1101 | len = size; |
| 1101 | else { | 1102 | else { |
| 1102 | 1103 | ||
| @@ -1142,7 +1143,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, | |||
| 1142 | data, fraggap, 0); | 1143 | data, fraggap, 0); |
| 1143 | skb_prev->csum = csum_sub(skb_prev->csum, | 1144 | skb_prev->csum = csum_sub(skb_prev->csum, |
| 1144 | skb->csum); | 1145 | skb->csum); |
| 1145 | skb_trim(skb_prev, maxfraglen); | 1146 | pskb_trim_unique(skb_prev, maxfraglen); |
| 1146 | } | 1147 | } |
| 1147 | 1148 | ||
| 1148 | /* | 1149 | /* |
| @@ -1339,7 +1340,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
| 1339 | char data[40]; | 1340 | char data[40]; |
| 1340 | } replyopts; | 1341 | } replyopts; |
| 1341 | struct ipcm_cookie ipc; | 1342 | struct ipcm_cookie ipc; |
| 1342 | u32 daddr; | 1343 | __be32 daddr; |
| 1343 | struct rtable *rt = (struct rtable*)skb->dst; | 1344 | struct rtable *rt = (struct rtable*)skb->dst; |
| 1344 | 1345 | ||
| 1345 | if (ip_options_echo(&replyopts.opt, skb)) | 1346 | if (ip_options_echo(&replyopts.opt, skb)) |
| @@ -1365,6 +1366,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
| 1365 | { .sport = skb->h.th->dest, | 1366 | { .sport = skb->h.th->dest, |
| 1366 | .dport = skb->h.th->source } }, | 1367 | .dport = skb->h.th->source } }, |
| 1367 | .proto = sk->sk_protocol }; | 1368 | .proto = sk->sk_protocol }; |
| 1369 | security_skb_classify_flow(skb, &fl); | ||
| 1368 | if (ip_route_output_key(&rt, &fl)) | 1370 | if (ip_route_output_key(&rt, &fl)) |
| 1369 | return; | 1371 | return; |
| 1370 | } | 1372 | } |
