aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c58
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
599void 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
599int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) 624int 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:
920static int ip6_dst_lookup_tail(struct sock *sk, 945static 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;