162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * INET		An implementation of the TCP/IP protocol suite for the LINUX
462306a36Sopenharmony_ci *		operating system.  INET is implemented using the  BSD Socket
562306a36Sopenharmony_ci *		interface as the means of communication with the user level.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *		PF_INET6 protocol dispatch tables.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Authors:	Pedro Roque	<roque@di.fc.ul.pt>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci *      Changes:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *      Vince Laviano (vince@cs.stanford.edu)       16 May 2001
1662306a36Sopenharmony_ci *      - Removed unused variable 'inet6_protocol_base'
1762306a36Sopenharmony_ci *      - Modified inet6_del_protocol() to correctly maintain copy bit.
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/netdevice.h>
2162306a36Sopenharmony_ci#include <linux/spinlock.h>
2262306a36Sopenharmony_ci#include <net/protocol.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
2562306a36Sopenharmony_cistruct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly;
2662306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_protos);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciint inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	return !cmpxchg((const struct inet6_protocol **)&inet6_protos[protocol],
3162306a36Sopenharmony_ci			NULL, prot) ? 0 : -1;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_add_protocol);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciint inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	int ret;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	ret = (cmpxchg((const struct inet6_protocol **)&inet6_protos[protocol],
4062306a36Sopenharmony_ci		       prot, NULL) == prot) ? 0 : -1;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	synchronize_net();
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return ret;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_del_protocol);
4762306a36Sopenharmony_ci#endif
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciconst struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly;
5062306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_offloads);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciint inet6_add_offload(const struct net_offload *prot, unsigned char protocol)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	return !cmpxchg((const struct net_offload **)&inet6_offloads[protocol],
5562306a36Sopenharmony_ci			NULL, prot) ? 0 : -1;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_add_offload);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciint inet6_del_offload(const struct net_offload *prot, unsigned char protocol)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	int ret;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	ret = (cmpxchg((const struct net_offload **)&inet6_offloads[protocol],
6462306a36Sopenharmony_ci		       prot, NULL) == prot) ? 0 : -1;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	synchronize_net();
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return ret;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ciEXPORT_SYMBOL(inet6_del_offload);
71