diff options
Diffstat (limited to 'net/ipv6/output_core.c')
-rw-r--r-- | net/ipv6/output_core.c | 36 |
1 files changed, 17 insertions, 19 deletions
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 827f795209c..56596ce390a 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c @@ -6,33 +6,31 @@ #include <net/ipv6.h> #include <net/ip6_fib.h> #include <net/addrconf.h> +#include <net/secure_seq.h> void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) { static atomic_t ipv6_fragmentation_id; - int old, new; + struct in6_addr addr; + int ident; #if IS_ENABLED(CONFIG_IPV6) - if (rt && !(rt->dst.flags & DST_NOPEER)) { - struct inet_peer *peer; - struct net *net; - - net = dev_net(rt->dst.dev); - peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); - if (peer) { - fhdr->identification = htonl(inet_getid(peer, 0)); - inet_putpeer(peer); - return; - } + struct inet_peer *peer; + struct net *net; + + net = dev_net(rt->dst.dev); + peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); + if (peer) { + fhdr->identification = htonl(inet_getid(peer, 0)); + inet_putpeer(peer); + return; } #endif - do { - old = atomic_read(&ipv6_fragmentation_id); - new = old + 1; - if (!new) - new = 1; - } while (atomic_cmpxchg(&ipv6_fragmentation_id, old, new) != old); - fhdr->identification = htonl(new); + ident = atomic_inc_return(&ipv6_fragmentation_id); + + addr = rt->rt6i_dst.addr; + addr.s6_addr32[0] ^= (__force __be32)ident; + fhdr->identification = htonl(secure_ipv6_id(addr.s6_addr32)); } EXPORT_SYMBOL(ipv6_select_ident); |