diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9d4b165837d6..32e5339db0c8 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -100,6 +100,7 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
100 | { | 100 | { |
101 | struct dst_entry *dst = skb_dst(skb); | 101 | struct dst_entry *dst = skb_dst(skb); |
102 | struct net_device *dev = dst->dev; | 102 | struct net_device *dev = dst->dev; |
103 | struct neighbour *neigh; | ||
103 | 104 | ||
104 | skb->protocol = htons(ETH_P_IPV6); | 105 | skb->protocol = htons(ETH_P_IPV6); |
105 | skb->dev = dev; | 106 | skb->dev = dev; |
@@ -134,10 +135,9 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
134 | skb->len); | 135 | skb->len); |
135 | } | 136 | } |
136 | 137 | ||
137 | if (dst->hh) | 138 | neigh = dst_get_neighbour(dst); |
138 | return neigh_hh_output(dst->hh, skb); | 139 | if (neigh) |
139 | else if (dst->neighbour) | 140 | return neigh_output(neigh, skb); |
140 | return dst->neighbour->output(skb); | ||
141 | 141 | ||
142 | IP6_INC_STATS_BH(dev_net(dst->dev), | 142 | IP6_INC_STATS_BH(dev_net(dst->dev), |
143 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 143 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
@@ -385,6 +385,7 @@ int ip6_forward(struct sk_buff *skb) | |||
385 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 385 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
386 | struct inet6_skb_parm *opt = IP6CB(skb); | 386 | struct inet6_skb_parm *opt = IP6CB(skb); |
387 | struct net *net = dev_net(dst->dev); | 387 | struct net *net = dev_net(dst->dev); |
388 | struct neighbour *n; | ||
388 | u32 mtu; | 389 | u32 mtu; |
389 | 390 | ||
390 | if (net->ipv6.devconf_all->forwarding == 0) | 391 | if (net->ipv6.devconf_all->forwarding == 0) |
@@ -459,11 +460,10 @@ int ip6_forward(struct sk_buff *skb) | |||
459 | send redirects to source routed frames. | 460 | send redirects to source routed frames. |
460 | We don't send redirects to frames decapsulated from IPsec. | 461 | We don't send redirects to frames decapsulated from IPsec. |
461 | */ | 462 | */ |
462 | if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 && | 463 | n = dst_get_neighbour(dst); |
463 | !skb_sec_path(skb)) { | 464 | if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) { |
464 | struct in6_addr *target = NULL; | 465 | struct in6_addr *target = NULL; |
465 | struct rt6_info *rt; | 466 | struct rt6_info *rt; |
466 | struct neighbour *n = dst->neighbour; | ||
467 | 467 | ||
468 | /* | 468 | /* |
469 | * incoming and outgoing devices are the same | 469 | * incoming and outgoing devices are the same |
@@ -596,6 +596,31 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | |||
596 | return offset; | 596 | return offset; |
597 | } | 597 | } |
598 | 598 | ||
599 | void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | ||
600 | { | ||
601 | static atomic_t ipv6_fragmentation_id; | ||
602 | int old, new; | ||
603 | |||
604 | if (rt) { | ||
605 | struct inet_peer *peer; | ||
606 | |||
607 | if (!rt->rt6i_peer) | ||
608 | rt6_bind_peer(rt, 1); | ||
609 | peer = rt->rt6i_peer; | ||
610 | if (peer) { | ||
611 | fhdr->identification = htonl(inet_getid(peer, 0)); | ||
612 | return; | ||
613 | } | ||
614 | } | ||
615 | do { | ||
616 | old = atomic_read(&ipv6_fragmentation_id); | ||
617 | new = old + 1; | ||
618 | if (!new) | ||
619 | new = 1; | ||
620 | } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old); | ||
621 | fhdr->identification = htonl(new); | ||
622 | } | ||
623 | |||
599 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | 624 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) |
600 | { | 625 | { |
601 | struct sk_buff *frag; | 626 | struct sk_buff *frag; |
@@ -680,7 +705,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
680 | skb_reset_network_header(skb); | 705 | skb_reset_network_header(skb); |
681 | memcpy(skb_network_header(skb), tmp_hdr, hlen); | 706 | memcpy(skb_network_header(skb), tmp_hdr, hlen); |
682 | 707 | ||
683 | ipv6_select_ident(fh); | 708 | ipv6_select_ident(fh, rt); |
684 | fh->nexthdr = nexthdr; | 709 | fh->nexthdr = nexthdr; |
685 | fh->reserved = 0; | 710 | fh->reserved = 0; |
686 | fh->frag_off = htons(IP6_MF); | 711 | fh->frag_off = htons(IP6_MF); |
@@ -826,7 +851,7 @@ slow_path: | |||
826 | fh->nexthdr = nexthdr; | 851 | fh->nexthdr = nexthdr; |
827 | fh->reserved = 0; | 852 | fh->reserved = 0; |
828 | if (!frag_id) { | 853 | if (!frag_id) { |
829 | ipv6_select_ident(fh); | 854 | ipv6_select_ident(fh, rt); |
830 | frag_id = fh->identification; | 855 | frag_id = fh->identification; |
831 | } else | 856 | } else |
832 | fh->identification = frag_id; | 857 | fh->identification = frag_id; |
@@ -920,8 +945,11 @@ out: | |||
920 | static int ip6_dst_lookup_tail(struct sock *sk, | 945 | static int ip6_dst_lookup_tail(struct sock *sk, |
921 | struct dst_entry **dst, struct flowi6 *fl6) | 946 | struct dst_entry **dst, struct flowi6 *fl6) |
922 | { | 947 | { |
923 | int err; | ||
924 | struct net *net = sock_net(sk); | 948 | struct net *net = sock_net(sk); |
949 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
950 | struct neighbour *n; | ||
951 | #endif | ||
952 | int err; | ||
925 | 953 | ||
926 | if (*dst == NULL) | 954 | if (*dst == NULL) |
927 | *dst = ip6_route_output(net, sk, fl6); | 955 | *dst = ip6_route_output(net, sk, fl6); |
@@ -947,7 +975,8 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
947 | * dst entry and replace it instead with the | 975 | * dst entry and replace it instead with the |
948 | * dst entry of the nexthop router | 976 | * dst entry of the nexthop router |
949 | */ | 977 | */ |
950 | if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) { | 978 | n = dst_get_neighbour(*dst); |
979 | if (n && !(n->nud_state & NUD_VALID)) { | ||
951 | struct inet6_ifaddr *ifp; | 980 | struct inet6_ifaddr *ifp; |
952 | struct flowi6 fl_gw6; | 981 | struct flowi6 fl_gw6; |
953 | int redirect; | 982 | int redirect; |
@@ -1072,7 +1101,8 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1072 | int getfrag(void *from, char *to, int offset, int len, | 1101 | int getfrag(void *from, char *to, int offset, int len, |
1073 | int odd, struct sk_buff *skb), | 1102 | int odd, struct sk_buff *skb), |
1074 | void *from, int length, int hh_len, int fragheaderlen, | 1103 | void *from, int length, int hh_len, int fragheaderlen, |
1075 | int transhdrlen, int mtu,unsigned int flags) | 1104 | int transhdrlen, int mtu,unsigned int flags, |
1105 | struct rt6_info *rt) | ||
1076 | 1106 | ||
1077 | { | 1107 | { |
1078 | struct sk_buff *skb; | 1108 | struct sk_buff *skb; |
@@ -1116,7 +1146,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1116 | skb_shinfo(skb)->gso_size = (mtu - fragheaderlen - | 1146 | skb_shinfo(skb)->gso_size = (mtu - fragheaderlen - |
1117 | sizeof(struct frag_hdr)) & ~7; | 1147 | sizeof(struct frag_hdr)) & ~7; |
1118 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; | 1148 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; |
1119 | ipv6_select_ident(&fhdr); | 1149 | ipv6_select_ident(&fhdr, rt); |
1120 | skb_shinfo(skb)->ip6_frag_id = fhdr.identification; | 1150 | skb_shinfo(skb)->ip6_frag_id = fhdr.identification; |
1121 | __skb_queue_tail(&sk->sk_write_queue, skb); | 1151 | __skb_queue_tail(&sk->sk_write_queue, skb); |
1122 | 1152 | ||
@@ -1282,7 +1312,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1282 | 1312 | ||
1283 | err = ip6_ufo_append_data(sk, getfrag, from, length, | 1313 | err = ip6_ufo_append_data(sk, getfrag, from, length, |
1284 | hh_len, fragheaderlen, | 1314 | hh_len, fragheaderlen, |
1285 | transhdrlen, mtu, flags); | 1315 | transhdrlen, mtu, flags, rt); |
1286 | if (err) | 1316 | if (err) |
1287 | goto error; | 1317 | goto error; |
1288 | return 0; | 1318 | return 0; |