diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 223 |
1 files changed, 139 insertions, 84 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 980912ed7a38..9d4b165837d6 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -56,7 +56,7 @@ | |||
56 | #include <net/checksum.h> | 56 | #include <net/checksum.h> |
57 | #include <linux/mroute6.h> | 57 | #include <linux/mroute6.h> |
58 | 58 | ||
59 | static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); | 59 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); |
60 | 60 | ||
61 | int __ip6_local_out(struct sk_buff *skb) | 61 | int __ip6_local_out(struct sk_buff *skb) |
62 | { | 62 | { |
@@ -145,14 +145,6 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
145 | return -EINVAL; | 145 | return -EINVAL; |
146 | } | 146 | } |
147 | 147 | ||
148 | static inline int ip6_skb_dst_mtu(struct sk_buff *skb) | ||
149 | { | ||
150 | struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; | ||
151 | |||
152 | return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ? | ||
153 | skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); | ||
154 | } | ||
155 | |||
156 | static int ip6_finish_output(struct sk_buff *skb) | 148 | static int ip6_finish_output(struct sk_buff *skb) |
157 | { | 149 | { |
158 | if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || | 150 | if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || |
@@ -182,15 +174,15 @@ int ip6_output(struct sk_buff *skb) | |||
182 | * xmit an sk_buff (used by TCP, SCTP and DCCP) | 174 | * xmit an sk_buff (used by TCP, SCTP and DCCP) |
183 | */ | 175 | */ |
184 | 176 | ||
185 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | 177 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, |
186 | struct ipv6_txoptions *opt) | 178 | struct ipv6_txoptions *opt) |
187 | { | 179 | { |
188 | struct net *net = sock_net(sk); | 180 | struct net *net = sock_net(sk); |
189 | struct ipv6_pinfo *np = inet6_sk(sk); | 181 | struct ipv6_pinfo *np = inet6_sk(sk); |
190 | struct in6_addr *first_hop = &fl->fl6_dst; | 182 | struct in6_addr *first_hop = &fl6->daddr; |
191 | struct dst_entry *dst = skb_dst(skb); | 183 | struct dst_entry *dst = skb_dst(skb); |
192 | struct ipv6hdr *hdr; | 184 | struct ipv6hdr *hdr; |
193 | u8 proto = fl->proto; | 185 | u8 proto = fl6->flowi6_proto; |
194 | int seg_len = skb->len; | 186 | int seg_len = skb->len; |
195 | int hlimit = -1; | 187 | int hlimit = -1; |
196 | int tclass = 0; | 188 | int tclass = 0; |
@@ -238,13 +230,13 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
238 | if (hlimit < 0) | 230 | if (hlimit < 0) |
239 | hlimit = ip6_dst_hoplimit(dst); | 231 | hlimit = ip6_dst_hoplimit(dst); |
240 | 232 | ||
241 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; | 233 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl6->flowlabel; |
242 | 234 | ||
243 | hdr->payload_len = htons(seg_len); | 235 | hdr->payload_len = htons(seg_len); |
244 | hdr->nexthdr = proto; | 236 | hdr->nexthdr = proto; |
245 | hdr->hop_limit = hlimit; | 237 | hdr->hop_limit = hlimit; |
246 | 238 | ||
247 | ipv6_addr_copy(&hdr->saddr, &fl->fl6_src); | 239 | ipv6_addr_copy(&hdr->saddr, &fl6->saddr); |
248 | ipv6_addr_copy(&hdr->daddr, first_hop); | 240 | ipv6_addr_copy(&hdr->daddr, first_hop); |
249 | 241 | ||
250 | skb->priority = sk->sk_priority; | 242 | skb->priority = sk->sk_priority; |
@@ -282,13 +274,10 @@ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, | |||
282 | { | 274 | { |
283 | struct ipv6_pinfo *np = inet6_sk(sk); | 275 | struct ipv6_pinfo *np = inet6_sk(sk); |
284 | struct ipv6hdr *hdr; | 276 | struct ipv6hdr *hdr; |
285 | int totlen; | ||
286 | 277 | ||
287 | skb->protocol = htons(ETH_P_IPV6); | 278 | skb->protocol = htons(ETH_P_IPV6); |
288 | skb->dev = dev; | 279 | skb->dev = dev; |
289 | 280 | ||
290 | totlen = len + sizeof(struct ipv6hdr); | ||
291 | |||
292 | skb_reset_network_header(skb); | 281 | skb_reset_network_header(skb); |
293 | skb_put(skb, sizeof(struct ipv6hdr)); | 282 | skb_put(skb, sizeof(struct ipv6hdr)); |
294 | hdr = ipv6_hdr(skb); | 283 | hdr = ipv6_hdr(skb); |
@@ -409,6 +398,9 @@ int ip6_forward(struct sk_buff *skb) | |||
409 | goto drop; | 398 | goto drop; |
410 | } | 399 | } |
411 | 400 | ||
401 | if (skb->pkt_type != PACKET_HOST) | ||
402 | goto drop; | ||
403 | |||
412 | skb_forward_csum(skb); | 404 | skb_forward_csum(skb); |
413 | 405 | ||
414 | /* | 406 | /* |
@@ -484,10 +476,13 @@ int ip6_forward(struct sk_buff *skb) | |||
484 | else | 476 | else |
485 | target = &hdr->daddr; | 477 | target = &hdr->daddr; |
486 | 478 | ||
479 | if (!rt->rt6i_peer) | ||
480 | rt6_bind_peer(rt, 1); | ||
481 | |||
487 | /* Limit redirects both by destination (here) | 482 | /* Limit redirects both by destination (here) |
488 | and by source (inside ndisc_send_redirect) | 483 | and by source (inside ndisc_send_redirect) |
489 | */ | 484 | */ |
490 | if (xrlim_allow(dst, 1*HZ)) | 485 | if (inet_peer_xrlim_allow(rt->rt6i_peer, 1*HZ)) |
491 | ndisc_send_redirect(skb, n, target); | 486 | ndisc_send_redirect(skb, n, target); |
492 | } else { | 487 | } else { |
493 | int addrtype = ipv6_addr_type(&hdr->saddr); | 488 | int addrtype = ipv6_addr_type(&hdr->saddr); |
@@ -601,7 +596,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | |||
601 | return offset; | 596 | return offset; |
602 | } | 597 | } |
603 | 598 | ||
604 | static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | 599 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) |
605 | { | 600 | { |
606 | struct sk_buff *frag; | 601 | struct sk_buff *frag; |
607 | struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); | 602 | struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); |
@@ -637,7 +632,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
637 | } | 632 | } |
638 | mtu -= hlen + sizeof(struct frag_hdr); | 633 | mtu -= hlen + sizeof(struct frag_hdr); |
639 | 634 | ||
640 | if (skb_has_frags(skb)) { | 635 | if (skb_has_frag_list(skb)) { |
641 | int first_len = skb_pagelen(skb); | 636 | int first_len = skb_pagelen(skb); |
642 | struct sk_buff *frag2; | 637 | struct sk_buff *frag2; |
643 | 638 | ||
@@ -784,7 +779,7 @@ slow_path: | |||
784 | /* IF: it doesn't fit, use 'mtu' - the data space left */ | 779 | /* IF: it doesn't fit, use 'mtu' - the data space left */ |
785 | if (len > mtu) | 780 | if (len > mtu) |
786 | len = mtu; | 781 | len = mtu; |
787 | /* IF: we are not sending upto and including the packet end | 782 | /* IF: we are not sending up to and including the packet end |
788 | then align the next start on an eight byte boundary */ | 783 | then align the next start on an eight byte boundary */ |
789 | if (len < left) { | 784 | if (len < left) { |
790 | len &= ~7; | 785 | len &= ~7; |
@@ -874,17 +869,17 @@ fail: | |||
874 | return err; | 869 | return err; |
875 | } | 870 | } |
876 | 871 | ||
877 | static inline int ip6_rt_check(struct rt6key *rt_key, | 872 | static inline int ip6_rt_check(const struct rt6key *rt_key, |
878 | struct in6_addr *fl_addr, | 873 | const struct in6_addr *fl_addr, |
879 | struct in6_addr *addr_cache) | 874 | const struct in6_addr *addr_cache) |
880 | { | 875 | { |
881 | return ((rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && | 876 | return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && |
882 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache))); | 877 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache)); |
883 | } | 878 | } |
884 | 879 | ||
885 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | 880 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, |
886 | struct dst_entry *dst, | 881 | struct dst_entry *dst, |
887 | struct flowi *fl) | 882 | const struct flowi6 *fl6) |
888 | { | 883 | { |
889 | struct ipv6_pinfo *np = inet6_sk(sk); | 884 | struct ipv6_pinfo *np = inet6_sk(sk); |
890 | struct rt6_info *rt = (struct rt6_info *)dst; | 885 | struct rt6_info *rt = (struct rt6_info *)dst; |
@@ -909,11 +904,11 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | |||
909 | * sockets. | 904 | * sockets. |
910 | * 2. oif also should be the same. | 905 | * 2. oif also should be the same. |
911 | */ | 906 | */ |
912 | if (ip6_rt_check(&rt->rt6i_dst, &fl->fl6_dst, np->daddr_cache) || | 907 | if (ip6_rt_check(&rt->rt6i_dst, &fl6->daddr, np->daddr_cache) || |
913 | #ifdef CONFIG_IPV6_SUBTREES | 908 | #ifdef CONFIG_IPV6_SUBTREES |
914 | ip6_rt_check(&rt->rt6i_src, &fl->fl6_src, np->saddr_cache) || | 909 | ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) || |
915 | #endif | 910 | #endif |
916 | (fl->oif && fl->oif != dst->dev->ifindex)) { | 911 | (fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex)) { |
917 | dst_release(dst); | 912 | dst_release(dst); |
918 | dst = NULL; | 913 | dst = NULL; |
919 | } | 914 | } |
@@ -923,22 +918,22 @@ out: | |||
923 | } | 918 | } |
924 | 919 | ||
925 | static int ip6_dst_lookup_tail(struct sock *sk, | 920 | static int ip6_dst_lookup_tail(struct sock *sk, |
926 | struct dst_entry **dst, struct flowi *fl) | 921 | struct dst_entry **dst, struct flowi6 *fl6) |
927 | { | 922 | { |
928 | int err; | 923 | int err; |
929 | struct net *net = sock_net(sk); | 924 | struct net *net = sock_net(sk); |
930 | 925 | ||
931 | if (*dst == NULL) | 926 | if (*dst == NULL) |
932 | *dst = ip6_route_output(net, sk, fl); | 927 | *dst = ip6_route_output(net, sk, fl6); |
933 | 928 | ||
934 | if ((err = (*dst)->error)) | 929 | if ((err = (*dst)->error)) |
935 | goto out_err_release; | 930 | goto out_err_release; |
936 | 931 | ||
937 | if (ipv6_addr_any(&fl->fl6_src)) { | 932 | if (ipv6_addr_any(&fl6->saddr)) { |
938 | err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev, | 933 | struct rt6_info *rt = (struct rt6_info *) *dst; |
939 | &fl->fl6_dst, | 934 | err = ip6_route_get_saddr(net, rt, &fl6->daddr, |
940 | sk ? inet6_sk(sk)->srcprefs : 0, | 935 | sk ? inet6_sk(sk)->srcprefs : 0, |
941 | &fl->fl6_src); | 936 | &fl6->saddr); |
942 | if (err) | 937 | if (err) |
943 | goto out_err_release; | 938 | goto out_err_release; |
944 | } | 939 | } |
@@ -954,10 +949,10 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
954 | */ | 949 | */ |
955 | if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) { | 950 | if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) { |
956 | struct inet6_ifaddr *ifp; | 951 | struct inet6_ifaddr *ifp; |
957 | struct flowi fl_gw; | 952 | struct flowi6 fl_gw6; |
958 | int redirect; | 953 | int redirect; |
959 | 954 | ||
960 | ifp = ipv6_get_ifaddr(net, &fl->fl6_src, | 955 | ifp = ipv6_get_ifaddr(net, &fl6->saddr, |
961 | (*dst)->dev, 1); | 956 | (*dst)->dev, 1); |
962 | 957 | ||
963 | redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); | 958 | redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); |
@@ -970,9 +965,9 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
970 | * default router instead | 965 | * default router instead |
971 | */ | 966 | */ |
972 | dst_release(*dst); | 967 | dst_release(*dst); |
973 | memcpy(&fl_gw, fl, sizeof(struct flowi)); | 968 | memcpy(&fl_gw6, fl6, sizeof(struct flowi6)); |
974 | memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr)); | 969 | memset(&fl_gw6.daddr, 0, sizeof(struct in6_addr)); |
975 | *dst = ip6_route_output(net, sk, &fl_gw); | 970 | *dst = ip6_route_output(net, sk, &fl_gw6); |
976 | if ((err = (*dst)->error)) | 971 | if ((err = (*dst)->error)) |
977 | goto out_err_release; | 972 | goto out_err_release; |
978 | } | 973 | } |
@@ -993,43 +988,85 @@ out_err_release: | |||
993 | * ip6_dst_lookup - perform route lookup on flow | 988 | * ip6_dst_lookup - perform route lookup on flow |
994 | * @sk: socket which provides route info | 989 | * @sk: socket which provides route info |
995 | * @dst: pointer to dst_entry * for result | 990 | * @dst: pointer to dst_entry * for result |
996 | * @fl: flow to lookup | 991 | * @fl6: flow to lookup |
997 | * | 992 | * |
998 | * This function performs a route lookup on the given flow. | 993 | * This function performs a route lookup on the given flow. |
999 | * | 994 | * |
1000 | * It returns zero on success, or a standard errno code on error. | 995 | * It returns zero on success, or a standard errno code on error. |
1001 | */ | 996 | */ |
1002 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | 997 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6) |
1003 | { | 998 | { |
1004 | *dst = NULL; | 999 | *dst = NULL; |
1005 | return ip6_dst_lookup_tail(sk, dst, fl); | 1000 | return ip6_dst_lookup_tail(sk, dst, fl6); |
1006 | } | 1001 | } |
1007 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); | 1002 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); |
1008 | 1003 | ||
1009 | /** | 1004 | /** |
1010 | * ip6_sk_dst_lookup - perform socket cached route lookup on flow | 1005 | * ip6_dst_lookup_flow - perform route lookup on flow with ipsec |
1006 | * @sk: socket which provides route info | ||
1007 | * @fl6: flow to lookup | ||
1008 | * @final_dst: final destination address for ipsec lookup | ||
1009 | * @can_sleep: we are in a sleepable context | ||
1010 | * | ||
1011 | * This function performs a route lookup on the given flow. | ||
1012 | * | ||
1013 | * It returns a valid dst pointer on success, or a pointer encoded | ||
1014 | * error code. | ||
1015 | */ | ||
1016 | struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | ||
1017 | const struct in6_addr *final_dst, | ||
1018 | bool can_sleep) | ||
1019 | { | ||
1020 | struct dst_entry *dst = NULL; | ||
1021 | int err; | ||
1022 | |||
1023 | err = ip6_dst_lookup_tail(sk, &dst, fl6); | ||
1024 | if (err) | ||
1025 | return ERR_PTR(err); | ||
1026 | if (final_dst) | ||
1027 | ipv6_addr_copy(&fl6->daddr, final_dst); | ||
1028 | if (can_sleep) | ||
1029 | fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; | ||
1030 | |||
1031 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); | ||
1032 | } | ||
1033 | EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); | ||
1034 | |||
1035 | /** | ||
1036 | * ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow | ||
1011 | * @sk: socket which provides the dst cache and route info | 1037 | * @sk: socket which provides the dst cache and route info |
1012 | * @dst: pointer to dst_entry * for result | 1038 | * @fl6: flow to lookup |
1013 | * @fl: flow to lookup | 1039 | * @final_dst: final destination address for ipsec lookup |
1040 | * @can_sleep: we are in a sleepable context | ||
1014 | * | 1041 | * |
1015 | * This function performs a route lookup on the given flow with the | 1042 | * This function performs a route lookup on the given flow with the |
1016 | * possibility of using the cached route in the socket if it is valid. | 1043 | * possibility of using the cached route in the socket if it is valid. |
1017 | * It will take the socket dst lock when operating on the dst cache. | 1044 | * It will take the socket dst lock when operating on the dst cache. |
1018 | * As a result, this function can only be used in process context. | 1045 | * As a result, this function can only be used in process context. |
1019 | * | 1046 | * |
1020 | * It returns zero on success, or a standard errno code on error. | 1047 | * It returns a valid dst pointer on success, or a pointer encoded |
1048 | * error code. | ||
1021 | */ | 1049 | */ |
1022 | int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | 1050 | struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, |
1051 | const struct in6_addr *final_dst, | ||
1052 | bool can_sleep) | ||
1023 | { | 1053 | { |
1024 | *dst = NULL; | 1054 | struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); |
1025 | if (sk) { | 1055 | int err; |
1026 | *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); | 1056 | |
1027 | *dst = ip6_sk_dst_check(sk, *dst, fl); | 1057 | dst = ip6_sk_dst_check(sk, dst, fl6); |
1028 | } | ||
1029 | 1058 | ||
1030 | return ip6_dst_lookup_tail(sk, dst, fl); | 1059 | err = ip6_dst_lookup_tail(sk, &dst, fl6); |
1060 | if (err) | ||
1061 | return ERR_PTR(err); | ||
1062 | if (final_dst) | ||
1063 | ipv6_addr_copy(&fl6->daddr, final_dst); | ||
1064 | if (can_sleep) | ||
1065 | fl6->flowi6_flags |= FLOWI_FLAG_CAN_SLEEP; | ||
1066 | |||
1067 | return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); | ||
1031 | } | 1068 | } |
1032 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup); | 1069 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); |
1033 | 1070 | ||
1034 | static inline int ip6_ufo_append_data(struct sock *sk, | 1071 | static inline int ip6_ufo_append_data(struct sock *sk, |
1035 | int getfrag(void *from, char *to, int offset, int len, | 1072 | int getfrag(void *from, char *to, int offset, int len, |
@@ -1066,7 +1103,6 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1066 | 1103 | ||
1067 | skb->ip_summed = CHECKSUM_PARTIAL; | 1104 | skb->ip_summed = CHECKSUM_PARTIAL; |
1068 | skb->csum = 0; | 1105 | skb->csum = 0; |
1069 | sk->sk_sndmsg_off = 0; | ||
1070 | } | 1106 | } |
1071 | 1107 | ||
1072 | err = skb_append_datato_frags(sk,skb, getfrag, from, | 1108 | err = skb_append_datato_frags(sk,skb, getfrag, from, |
@@ -1109,11 +1145,12 @@ static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src, | |||
1109 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | 1145 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, |
1110 | int offset, int len, int odd, struct sk_buff *skb), | 1146 | int offset, int len, int odd, struct sk_buff *skb), |
1111 | void *from, int length, int transhdrlen, | 1147 | void *from, int length, int transhdrlen, |
1112 | int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl, | 1148 | int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6, |
1113 | struct rt6_info *rt, unsigned int flags, int dontfrag) | 1149 | struct rt6_info *rt, unsigned int flags, int dontfrag) |
1114 | { | 1150 | { |
1115 | struct inet_sock *inet = inet_sk(sk); | 1151 | struct inet_sock *inet = inet_sk(sk); |
1116 | struct ipv6_pinfo *np = inet6_sk(sk); | 1152 | struct ipv6_pinfo *np = inet6_sk(sk); |
1153 | struct inet_cork *cork; | ||
1117 | struct sk_buff *skb; | 1154 | struct sk_buff *skb; |
1118 | unsigned int maxfraglen, fragheaderlen; | 1155 | unsigned int maxfraglen, fragheaderlen; |
1119 | int exthdrlen; | 1156 | int exthdrlen; |
@@ -1123,9 +1160,11 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1123 | int err; | 1160 | int err; |
1124 | int offset = 0; | 1161 | int offset = 0; |
1125 | int csummode = CHECKSUM_NONE; | 1162 | int csummode = CHECKSUM_NONE; |
1163 | __u8 tx_flags = 0; | ||
1126 | 1164 | ||
1127 | if (flags&MSG_PROBE) | 1165 | if (flags&MSG_PROBE) |
1128 | return 0; | 1166 | return 0; |
1167 | cork = &inet->cork.base; | ||
1129 | if (skb_queue_empty(&sk->sk_write_queue)) { | 1168 | if (skb_queue_empty(&sk->sk_write_queue)) { |
1130 | /* | 1169 | /* |
1131 | * setup for corking | 1170 | * setup for corking |
@@ -1165,8 +1204,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1165 | /* need source address above miyazawa*/ | 1204 | /* need source address above miyazawa*/ |
1166 | } | 1205 | } |
1167 | dst_hold(&rt->dst); | 1206 | dst_hold(&rt->dst); |
1168 | inet->cork.dst = &rt->dst; | 1207 | cork->dst = &rt->dst; |
1169 | inet->cork.fl = *fl; | 1208 | inet->cork.fl.u.ip6 = *fl6; |
1170 | np->cork.hop_limit = hlimit; | 1209 | np->cork.hop_limit = hlimit; |
1171 | np->cork.tclass = tclass; | 1210 | np->cork.tclass = tclass; |
1172 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? | 1211 | mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? |
@@ -1175,10 +1214,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1175 | if (np->frag_size) | 1214 | if (np->frag_size) |
1176 | mtu = np->frag_size; | 1215 | mtu = np->frag_size; |
1177 | } | 1216 | } |
1178 | inet->cork.fragsize = mtu; | 1217 | cork->fragsize = mtu; |
1179 | if (dst_allfrag(rt->dst.path)) | 1218 | if (dst_allfrag(rt->dst.path)) |
1180 | inet->cork.flags |= IPCORK_ALLFRAG; | 1219 | cork->flags |= IPCORK_ALLFRAG; |
1181 | inet->cork.length = 0; | 1220 | cork->length = 0; |
1182 | sk->sk_sndmsg_page = NULL; | 1221 | sk->sk_sndmsg_page = NULL; |
1183 | sk->sk_sndmsg_off = 0; | 1222 | sk->sk_sndmsg_off = 0; |
1184 | exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) - | 1223 | exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) - |
@@ -1186,12 +1225,12 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1186 | length += exthdrlen; | 1225 | length += exthdrlen; |
1187 | transhdrlen += exthdrlen; | 1226 | transhdrlen += exthdrlen; |
1188 | } else { | 1227 | } else { |
1189 | rt = (struct rt6_info *)inet->cork.dst; | 1228 | rt = (struct rt6_info *)cork->dst; |
1190 | fl = &inet->cork.fl; | 1229 | fl6 = &inet->cork.fl.u.ip6; |
1191 | opt = np->cork.opt; | 1230 | opt = np->cork.opt; |
1192 | transhdrlen = 0; | 1231 | transhdrlen = 0; |
1193 | exthdrlen = 0; | 1232 | exthdrlen = 0; |
1194 | mtu = inet->cork.fragsize; | 1233 | mtu = cork->fragsize; |
1195 | } | 1234 | } |
1196 | 1235 | ||
1197 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); | 1236 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); |
@@ -1201,12 +1240,19 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1201 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); | 1240 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); |
1202 | 1241 | ||
1203 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { | 1242 | if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) { |
1204 | if (inet->cork.length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) { | 1243 | if (cork->length + length > sizeof(struct ipv6hdr) + IPV6_MAXPLEN - fragheaderlen) { |
1205 | ipv6_local_error(sk, EMSGSIZE, fl, mtu-exthdrlen); | 1244 | ipv6_local_error(sk, EMSGSIZE, fl6, mtu-exthdrlen); |
1206 | return -EMSGSIZE; | 1245 | return -EMSGSIZE; |
1207 | } | 1246 | } |
1208 | } | 1247 | } |
1209 | 1248 | ||
1249 | /* For UDP, check if TX timestamp is enabled */ | ||
1250 | if (sk->sk_type == SOCK_DGRAM) { | ||
1251 | err = sock_tx_timestamp(sk, &tx_flags); | ||
1252 | if (err) | ||
1253 | goto error; | ||
1254 | } | ||
1255 | |||
1210 | /* | 1256 | /* |
1211 | * Let's try using as much space as possible. | 1257 | * Let's try using as much space as possible. |
1212 | * Use MTU if total length of the message fits into the MTU. | 1258 | * Use MTU if total length of the message fits into the MTU. |
@@ -1223,11 +1269,11 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1223 | * --yoshfuji | 1269 | * --yoshfuji |
1224 | */ | 1270 | */ |
1225 | 1271 | ||
1226 | inet->cork.length += length; | 1272 | cork->length += length; |
1227 | if (length > mtu) { | 1273 | if (length > mtu) { |
1228 | int proto = sk->sk_protocol; | 1274 | int proto = sk->sk_protocol; |
1229 | if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){ | 1275 | if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){ |
1230 | ipv6_local_rxpmtu(sk, fl, mtu-exthdrlen); | 1276 | ipv6_local_rxpmtu(sk, fl6, mtu-exthdrlen); |
1231 | return -EMSGSIZE; | 1277 | return -EMSGSIZE; |
1232 | } | 1278 | } |
1233 | 1279 | ||
@@ -1248,7 +1294,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1248 | 1294 | ||
1249 | while (length > 0) { | 1295 | while (length > 0) { |
1250 | /* Check if the remaining data fits into current packet. */ | 1296 | /* Check if the remaining data fits into current packet. */ |
1251 | copy = (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len; | 1297 | copy = (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len; |
1252 | if (copy < length) | 1298 | if (copy < length) |
1253 | copy = maxfraglen - skb->len; | 1299 | copy = maxfraglen - skb->len; |
1254 | 1300 | ||
@@ -1273,7 +1319,7 @@ alloc_new_skb: | |||
1273 | * we know we need more fragment(s). | 1319 | * we know we need more fragment(s). |
1274 | */ | 1320 | */ |
1275 | datalen = length + fraggap; | 1321 | datalen = length + fraggap; |
1276 | if (datalen > (inet->cork.length <= mtu && !(inet->cork.flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) | 1322 | if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) |
1277 | datalen = maxfraglen - fragheaderlen; | 1323 | datalen = maxfraglen - fragheaderlen; |
1278 | 1324 | ||
1279 | fraglen = datalen + fragheaderlen; | 1325 | fraglen = datalen + fragheaderlen; |
@@ -1311,6 +1357,12 @@ alloc_new_skb: | |||
1311 | sk->sk_allocation); | 1357 | sk->sk_allocation); |
1312 | if (unlikely(skb == NULL)) | 1358 | if (unlikely(skb == NULL)) |
1313 | err = -ENOBUFS; | 1359 | err = -ENOBUFS; |
1360 | else { | ||
1361 | /* Only the initial fragment | ||
1362 | * is time stamped. | ||
1363 | */ | ||
1364 | tx_flags = 0; | ||
1365 | } | ||
1314 | } | 1366 | } |
1315 | if (skb == NULL) | 1367 | if (skb == NULL) |
1316 | goto error; | 1368 | goto error; |
@@ -1322,6 +1374,9 @@ alloc_new_skb: | |||
1322 | /* reserve for fragmentation */ | 1374 | /* reserve for fragmentation */ |
1323 | skb_reserve(skb, hh_len+sizeof(struct frag_hdr)); | 1375 | skb_reserve(skb, hh_len+sizeof(struct frag_hdr)); |
1324 | 1376 | ||
1377 | if (sk->sk_type == SOCK_DGRAM) | ||
1378 | skb_shinfo(skb)->tx_flags = tx_flags; | ||
1379 | |||
1325 | /* | 1380 | /* |
1326 | * Find where to start putting bytes | 1381 | * Find where to start putting bytes |
1327 | */ | 1382 | */ |
@@ -1428,7 +1483,7 @@ alloc_new_skb: | |||
1428 | } | 1483 | } |
1429 | return 0; | 1484 | return 0; |
1430 | error: | 1485 | error: |
1431 | inet->cork.length -= length; | 1486 | cork->length -= length; |
1432 | IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); | 1487 | IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); |
1433 | return err; | 1488 | return err; |
1434 | } | 1489 | } |
@@ -1444,10 +1499,10 @@ static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) | |||
1444 | np->cork.opt = NULL; | 1499 | np->cork.opt = NULL; |
1445 | } | 1500 | } |
1446 | 1501 | ||
1447 | if (inet->cork.dst) { | 1502 | if (inet->cork.base.dst) { |
1448 | dst_release(inet->cork.dst); | 1503 | dst_release(inet->cork.base.dst); |
1449 | inet->cork.dst = NULL; | 1504 | inet->cork.base.dst = NULL; |
1450 | inet->cork.flags &= ~IPCORK_ALLFRAG; | 1505 | inet->cork.base.flags &= ~IPCORK_ALLFRAG; |
1451 | } | 1506 | } |
1452 | memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); | 1507 | memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); |
1453 | } | 1508 | } |
@@ -1462,9 +1517,9 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1462 | struct net *net = sock_net(sk); | 1517 | struct net *net = sock_net(sk); |
1463 | struct ipv6hdr *hdr; | 1518 | struct ipv6hdr *hdr; |
1464 | struct ipv6_txoptions *opt = np->cork.opt; | 1519 | struct ipv6_txoptions *opt = np->cork.opt; |
1465 | struct rt6_info *rt = (struct rt6_info *)inet->cork.dst; | 1520 | struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst; |
1466 | struct flowi *fl = &inet->cork.fl; | 1521 | struct flowi6 *fl6 = &inet->cork.fl.u.ip6; |
1467 | unsigned char proto = fl->proto; | 1522 | unsigned char proto = fl6->flowi6_proto; |
1468 | int err = 0; | 1523 | int err = 0; |
1469 | 1524 | ||
1470 | if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL) | 1525 | if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL) |
@@ -1489,7 +1544,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1489 | if (np->pmtudisc < IPV6_PMTUDISC_DO) | 1544 | if (np->pmtudisc < IPV6_PMTUDISC_DO) |
1490 | skb->local_df = 1; | 1545 | skb->local_df = 1; |
1491 | 1546 | ||
1492 | ipv6_addr_copy(final_dst, &fl->fl6_dst); | 1547 | ipv6_addr_copy(final_dst, &fl6->daddr); |
1493 | __skb_pull(skb, skb_network_header_len(skb)); | 1548 | __skb_pull(skb, skb_network_header_len(skb)); |
1494 | if (opt && opt->opt_flen) | 1549 | if (opt && opt->opt_flen) |
1495 | ipv6_push_frag_opts(skb, opt, &proto); | 1550 | ipv6_push_frag_opts(skb, opt, &proto); |
@@ -1500,12 +1555,12 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1500 | skb_reset_network_header(skb); | 1555 | skb_reset_network_header(skb); |
1501 | hdr = ipv6_hdr(skb); | 1556 | hdr = ipv6_hdr(skb); |
1502 | 1557 | ||
1503 | *(__be32*)hdr = fl->fl6_flowlabel | | 1558 | *(__be32*)hdr = fl6->flowlabel | |
1504 | htonl(0x60000000 | ((int)np->cork.tclass << 20)); | 1559 | htonl(0x60000000 | ((int)np->cork.tclass << 20)); |
1505 | 1560 | ||
1506 | hdr->hop_limit = np->cork.hop_limit; | 1561 | hdr->hop_limit = np->cork.hop_limit; |
1507 | hdr->nexthdr = proto; | 1562 | hdr->nexthdr = proto; |
1508 | ipv6_addr_copy(&hdr->saddr, &fl->fl6_src); | 1563 | ipv6_addr_copy(&hdr->saddr, &fl6->saddr); |
1509 | ipv6_addr_copy(&hdr->daddr, final_dst); | 1564 | ipv6_addr_copy(&hdr->daddr, final_dst); |
1510 | 1565 | ||
1511 | skb->priority = sk->sk_priority; | 1566 | skb->priority = sk->sk_priority; |