2019-05-27 14:55:01 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* IPv6 BSD socket options interface
|
2007-02-09 22:24:49 +08:00
|
|
|
* Linux INET6 implementation
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* Authors:
|
2007-02-09 22:24:49 +08:00
|
|
|
* Pedro Roque <roque@di.fc.ul.pt>
|
2005-04-17 06:20:36 +08:00
|
|
|
*
|
|
|
|
* Based on linux/net/ipv4/ip_sockglue.c
|
|
|
|
*
|
|
|
|
* FIXME: Make the setsockopt code POSIX compliant: That is
|
|
|
|
*
|
|
|
|
* o Truncate getsockopt returns
|
|
|
|
* o Return an optlen of the truncated length if need be
|
|
|
|
*
|
|
|
|
* Changes:
|
|
|
|
* David L Stevens <dlstevens@us.ibm.com>:
|
|
|
|
* - added multicast source filtering API for MLDv2
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
2006-01-12 04:17:47 +08:00
|
|
|
#include <linux/capability.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/socket.h>
|
|
|
|
#include <linux/sockios.h>
|
|
|
|
#include <linux/net.h>
|
|
|
|
#include <linux/in6.h>
|
2008-04-03 08:22:53 +08:00
|
|
|
#include <linux/mroute6.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/if_arp.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/sysctl.h>
|
|
|
|
#include <linux/netfilter.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/snmp.h>
|
|
|
|
#include <net/ipv6.h>
|
|
|
|
#include <net/ndisc.h>
|
|
|
|
#include <net/protocol.h>
|
|
|
|
#include <net/transp_v6.h>
|
|
|
|
#include <net/ip6_route.h>
|
|
|
|
#include <net/addrconf.h>
|
|
|
|
#include <net/inet_common.h>
|
|
|
|
#include <net/tcp.h>
|
|
|
|
#include <net/udp.h>
|
2006-11-28 03:10:57 +08:00
|
|
|
#include <net/udplite.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <net/xfrm.h>
|
2008-04-27 16:06:07 +08:00
|
|
|
#include <net/compat.h>
|
2016-11-08 21:59:21 +08:00
|
|
|
#include <net/seg6.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2016-12-25 03:46:01 +08:00
|
|
|
#include <linux/uaccess.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
struct ip6_ra_chain *ip6_ra_chain;
|
|
|
|
DEFINE_RWLOCK(ip6_ra_lock);
|
|
|
|
|
2021-10-26 00:48:22 +08:00
|
|
|
DEFINE_STATIC_KEY_FALSE(ip6_min_hopcount);
|
|
|
|
|
2008-07-19 15:28:58 +08:00
|
|
|
int ip6_ra_control(struct sock *sk, int sel)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct ip6_ra_chain *ra, *new_ra, **rap;
|
|
|
|
|
|
|
|
/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
|
2009-10-15 14:30:45 +08:00
|
|
|
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW)
|
2008-06-12 02:27:26 +08:00
|
|
|
return -ENOPROTOOPT;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-08-25 04:53:10 +08:00
|
|
|
new_ra = (sel >= 0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
|
2019-05-24 11:19:46 +08:00
|
|
|
if (sel >= 0 && !new_ra)
|
|
|
|
return -ENOMEM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
write_lock_bh(&ip6_ra_lock);
|
2014-08-25 04:53:10 +08:00
|
|
|
for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
|
2005-04-17 06:20:36 +08:00
|
|
|
if (ra->sk == sk) {
|
2014-08-25 04:53:10 +08:00
|
|
|
if (sel >= 0) {
|
2005-04-17 06:20:36 +08:00
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
2005-11-09 01:41:34 +08:00
|
|
|
kfree(new_ra);
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EADDRINUSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rap = ra->next;
|
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
|
|
|
|
|
|
|
sock_put(sk);
|
|
|
|
kfree(ra);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2015-03-29 21:00:04 +08:00
|
|
|
if (!new_ra) {
|
2005-04-17 06:20:36 +08:00
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
new_ra->sk = sk;
|
|
|
|
new_ra->sel = sel;
|
|
|
|
new_ra->next = ra;
|
|
|
|
*rap = new_ra;
|
|
|
|
sock_hold(sk);
|
|
|
|
write_unlock_bh(&ip6_ra_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-14 14:21:52 +08:00
|
|
|
struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
|
|
|
|
struct ipv6_txoptions *opt)
|
|
|
|
{
|
2023-08-16 16:15:42 +08:00
|
|
|
if (inet_test_bit(IS_ICSK, sk)) {
|
2008-04-14 14:21:52 +08:00
|
|
|
if (opt &&
|
|
|
|
!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
|
2009-10-15 14:30:45 +08:00
|
|
|
inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) {
|
2008-04-14 14:21:52 +08:00
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
|
|
|
icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
|
|
|
|
icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
|
|
|
|
}
|
|
|
|
}
|
2015-11-30 11:37:57 +08:00
|
|
|
opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
|
|
|
|
opt);
|
2008-04-14 14:21:52 +08:00
|
|
|
sk_dst_reset(sk);
|
|
|
|
|
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
|
2015-03-19 01:50:42 +08:00
|
|
|
static bool setsockopt_needs_rtnl(int optname)
|
|
|
|
{
|
|
|
|
switch (optname) {
|
2016-10-20 14:35:12 +08:00
|
|
|
case IPV6_ADDRFORM:
|
2015-03-19 01:50:42 +08:00
|
|
|
case IPV6_ADD_MEMBERSHIP:
|
|
|
|
case IPV6_DROP_MEMBERSHIP:
|
2015-03-20 22:37:17 +08:00
|
|
|
case IPV6_JOIN_ANYCAST:
|
|
|
|
case IPV6_LEAVE_ANYCAST:
|
2015-03-19 01:50:42 +08:00
|
|
|
case MCAST_JOIN_GROUP:
|
|
|
|
case MCAST_LEAVE_GROUP:
|
ipv4, ipv6: kill ip_mc_{join, leave}_group and ipv6_sock_mc_{join, drop}
in favor of their inner __ ones, which doesn't grab rtnl.
As these functions need to operate on a locked socket, we can't be
grabbing rtnl by then. It's too late and doing so causes reversed
locking.
So this patch:
- move rtnl handling to callers instead while already fixing some
reversed locking situations, like on vxlan and ipvs code.
- renames __ ones to not have the __ mark:
__ip_mc_{join,leave}_group -> ip_mc_{join,leave}_group
__ipv6_sock_mc_{join,drop} -> ipv6_sock_mc_{join,drop}
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-19 01:50:43 +08:00
|
|
|
case MCAST_JOIN_SOURCE_GROUP:
|
|
|
|
case MCAST_LEAVE_SOURCE_GROUP:
|
|
|
|
case MCAST_BLOCK_SOURCE:
|
|
|
|
case MCAST_UNBLOCK_SOURCE:
|
|
|
|
case MCAST_MSFILTER:
|
2015-03-19 01:50:42 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-07-23 14:09:03 +08:00
|
|
|
static int copy_group_source_from_sockptr(struct group_source_req *greqs,
|
|
|
|
sockptr_t optval, int optlen)
|
2020-07-17 14:23:30 +08:00
|
|
|
{
|
|
|
|
if (in_compat_syscall()) {
|
|
|
|
struct compat_group_source_req gr32;
|
|
|
|
|
|
|
|
if (optlen < sizeof(gr32))
|
|
|
|
return -EINVAL;
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
|
2020-07-17 14:23:30 +08:00
|
|
|
return -EFAULT;
|
|
|
|
greqs->gsr_interface = gr32.gsr_interface;
|
|
|
|
greqs->gsr_group = gr32.gsr_group;
|
|
|
|
greqs->gsr_source = gr32.gsr_source;
|
|
|
|
} else {
|
|
|
|
if (optlen < sizeof(*greqs))
|
|
|
|
return -EINVAL;
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(greqs, optval, sizeof(*greqs)))
|
2020-07-17 14:23:30 +08:00
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-27 23:00:01 +08:00
|
|
|
static int do_ipv6_mcast_group_source(struct sock *sk, int optname,
|
2020-07-23 14:09:03 +08:00
|
|
|
sockptr_t optval, int optlen)
|
2020-04-27 23:00:01 +08:00
|
|
|
{
|
2020-07-17 14:23:30 +08:00
|
|
|
struct group_source_req greqs;
|
2020-04-27 23:00:01 +08:00
|
|
|
int omode, add;
|
2020-07-17 14:23:30 +08:00
|
|
|
int ret;
|
|
|
|
|
2020-07-23 14:09:03 +08:00
|
|
|
ret = copy_group_source_from_sockptr(&greqs, optval, optlen);
|
2020-07-17 14:23:30 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2020-04-27 23:00:01 +08:00
|
|
|
|
2020-07-17 14:23:30 +08:00
|
|
|
if (greqs.gsr_group.ss_family != AF_INET6 ||
|
|
|
|
greqs.gsr_source.ss_family != AF_INET6)
|
2020-04-27 23:00:01 +08:00
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
|
|
|
|
if (optname == MCAST_BLOCK_SOURCE) {
|
|
|
|
omode = MCAST_EXCLUDE;
|
|
|
|
add = 1;
|
|
|
|
} else if (optname == MCAST_UNBLOCK_SOURCE) {
|
|
|
|
omode = MCAST_EXCLUDE;
|
|
|
|
add = 0;
|
|
|
|
} else if (optname == MCAST_JOIN_SOURCE_GROUP) {
|
|
|
|
struct sockaddr_in6 *psin6;
|
|
|
|
int retv;
|
|
|
|
|
2020-07-17 14:23:30 +08:00
|
|
|
psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
|
|
|
|
retv = ipv6_sock_mc_join_ssm(sk, greqs.gsr_interface,
|
2020-04-27 23:00:01 +08:00
|
|
|
&psin6->sin6_addr,
|
|
|
|
MCAST_INCLUDE);
|
|
|
|
/* prior join w/ different source is ok */
|
|
|
|
if (retv && retv != -EADDRINUSE)
|
|
|
|
return retv;
|
|
|
|
omode = MCAST_INCLUDE;
|
|
|
|
add = 1;
|
|
|
|
} else /* MCAST_LEAVE_SOURCE_GROUP */ {
|
|
|
|
omode = MCAST_INCLUDE;
|
|
|
|
add = 0;
|
|
|
|
}
|
2020-07-17 14:23:30 +08:00
|
|
|
return ip6_mc_source(add, omode, sk, &greqs);
|
2020-04-27 23:00:01 +08:00
|
|
|
}
|
|
|
|
|
2020-07-23 14:09:03 +08:00
|
|
|
static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
|
2020-07-17 14:23:28 +08:00
|
|
|
int optlen)
|
|
|
|
{
|
|
|
|
struct group_filter *gsf;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (optlen < GROUP_FILTER_SIZE(0))
|
|
|
|
return -EINVAL;
|
2023-12-14 18:49:00 +08:00
|
|
|
if (optlen > READ_ONCE(sock_net(sk)->core.sysctl_optmem_max))
|
2020-07-17 14:23:28 +08:00
|
|
|
return -ENOBUFS;
|
|
|
|
|
2020-07-23 14:09:03 +08:00
|
|
|
gsf = memdup_sockptr(optval, optlen);
|
2020-07-17 14:23:28 +08:00
|
|
|
if (IS_ERR(gsf))
|
|
|
|
return PTR_ERR(gsf);
|
|
|
|
|
|
|
|
/* numsrc >= (4G-140)/128 overflow in 32 bits */
|
|
|
|
ret = -ENOBUFS;
|
|
|
|
if (gsf->gf_numsrc >= 0x1ffffffU ||
|
|
|
|
gsf->gf_numsrc > sysctl_mld_max_msf)
|
|
|
|
goto out_free_gsf;
|
|
|
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen)
|
|
|
|
goto out_free_gsf;
|
|
|
|
|
2021-08-05 04:45:36 +08:00
|
|
|
ret = ip6_mc_msfilter(sk, gsf, gsf->gf_slist_flex);
|
2020-07-17 14:23:28 +08:00
|
|
|
out_free_gsf:
|
|
|
|
kfree(gsf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-07-23 14:09:03 +08:00
|
|
|
static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
|
2020-07-17 14:23:28 +08:00
|
|
|
int optlen)
|
|
|
|
{
|
2021-08-05 04:45:36 +08:00
|
|
|
const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
|
2020-07-17 14:23:28 +08:00
|
|
|
struct compat_group_filter *gf32;
|
|
|
|
void *p;
|
|
|
|
int ret;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if (optlen < size0)
|
|
|
|
return -EINVAL;
|
2023-12-14 18:49:00 +08:00
|
|
|
if (optlen > READ_ONCE(sock_net(sk)->core.sysctl_optmem_max) - 4)
|
2020-07-17 14:23:28 +08:00
|
|
|
return -ENOBUFS;
|
|
|
|
|
|
|
|
p = kmalloc(optlen + 4, GFP_KERNEL);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2021-08-05 04:45:36 +08:00
|
|
|
gf32 = p + 4; /* we want ->gf_group and ->gf_slist_flex aligned */
|
2020-07-17 14:23:28 +08:00
|
|
|
ret = -EFAULT;
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(gf32, optval, optlen))
|
2020-07-17 14:23:28 +08:00
|
|
|
goto out_free_p;
|
|
|
|
|
|
|
|
/* numsrc >= (4G-140)/128 overflow in 32 bits */
|
|
|
|
ret = -ENOBUFS;
|
|
|
|
n = gf32->gf_numsrc;
|
|
|
|
if (n >= 0x1ffffffU || n > sysctl_mld_max_msf)
|
|
|
|
goto out_free_p;
|
|
|
|
|
|
|
|
ret = -EINVAL;
|
2021-08-05 04:45:36 +08:00
|
|
|
if (offsetof(struct compat_group_filter, gf_slist_flex[n]) > optlen)
|
2020-07-17 14:23:28 +08:00
|
|
|
goto out_free_p;
|
|
|
|
|
|
|
|
ret = ip6_mc_msfilter(sk, &(struct group_filter){
|
|
|
|
.gf_interface = gf32->gf_interface,
|
|
|
|
.gf_group = gf32->gf_group,
|
|
|
|
.gf_fmode = gf32->gf_fmode,
|
2021-08-05 04:45:36 +08:00
|
|
|
.gf_numsrc = gf32->gf_numsrc}, gf32->gf_slist_flex);
|
2020-07-17 14:23:28 +08:00
|
|
|
|
|
|
|
out_free_p:
|
|
|
|
kfree(p);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-07-17 14:23:29 +08:00
|
|
|
static int ipv6_mcast_join_leave(struct sock *sk, int optname,
|
2020-07-23 14:09:03 +08:00
|
|
|
sockptr_t optval, int optlen)
|
2020-07-17 14:23:29 +08:00
|
|
|
{
|
|
|
|
struct sockaddr_in6 *psin6;
|
|
|
|
struct group_req greq;
|
|
|
|
|
|
|
|
if (optlen < sizeof(greq))
|
|
|
|
return -EINVAL;
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(&greq, optval, sizeof(greq)))
|
2020-07-17 14:23:29 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (greq.gr_group.ss_family != AF_INET6)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
psin6 = (struct sockaddr_in6 *)&greq.gr_group;
|
|
|
|
if (optname == MCAST_JOIN_GROUP)
|
|
|
|
return ipv6_sock_mc_join(sk, greq.gr_interface,
|
|
|
|
&psin6->sin6_addr);
|
|
|
|
return ipv6_sock_mc_drop(sk, greq.gr_interface, &psin6->sin6_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compat_ipv6_mcast_join_leave(struct sock *sk, int optname,
|
2020-07-23 14:09:03 +08:00
|
|
|
sockptr_t optval, int optlen)
|
2020-07-17 14:23:29 +08:00
|
|
|
{
|
|
|
|
struct compat_group_req gr32;
|
|
|
|
struct sockaddr_in6 *psin6;
|
|
|
|
|
|
|
|
if (optlen < sizeof(gr32))
|
|
|
|
return -EINVAL;
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
|
2020-07-17 14:23:29 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (gr32.gr_group.ss_family != AF_INET6)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
psin6 = (struct sockaddr_in6 *)&gr32.gr_group;
|
|
|
|
if (optname == MCAST_JOIN_GROUP)
|
2020-07-17 14:23:30 +08:00
|
|
|
return ipv6_sock_mc_join(sk, gr32.gr_interface,
|
2020-07-17 14:23:29 +08:00
|
|
|
&psin6->sin6_addr);
|
2020-07-17 14:23:30 +08:00
|
|
|
return ipv6_sock_mc_drop(sk, gr32.gr_interface, &psin6->sin6_addr);
|
2020-07-17 14:23:29 +08:00
|
|
|
}
|
|
|
|
|
2020-07-23 14:09:03 +08:00
|
|
|
static int ipv6_set_opt_hdr(struct sock *sk, int optname, sockptr_t optval,
|
2020-07-23 14:09:02 +08:00
|
|
|
int optlen)
|
|
|
|
{
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
|
struct ipv6_opt_hdr *new = NULL;
|
|
|
|
struct net *net = sock_net(sk);
|
|
|
|
struct ipv6_txoptions *opt;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* hop-by-hop / destination options are privileged option */
|
2022-08-17 14:17:44 +08:00
|
|
|
if (optname != IPV6_RTHDR && !sockopt_ns_capable(net->user_ns, CAP_NET_RAW))
|
2020-07-23 14:09:02 +08:00
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
/* remove any sticky options header with a zero option
|
|
|
|
* length, per RFC3542.
|
|
|
|
*/
|
|
|
|
if (optlen > 0) {
|
2020-07-23 14:09:03 +08:00
|
|
|
if (sockptr_is_null(optval))
|
2020-07-23 14:09:02 +08:00
|
|
|
return -EINVAL;
|
|
|
|
if (optlen < sizeof(struct ipv6_opt_hdr) ||
|
|
|
|
optlen & 0x7 ||
|
|
|
|
optlen > 8 * 255)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-07-23 14:09:03 +08:00
|
|
|
new = memdup_sockptr(optval, optlen);
|
2020-07-23 14:09:02 +08:00
|
|
|
if (IS_ERR(new))
|
|
|
|
return PTR_ERR(new);
|
|
|
|
if (unlikely(ipv6_optlen(new) > optlen)) {
|
|
|
|
kfree(new);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
|
|
|
|
opt = ipv6_renew_options(sk, opt, optname, new);
|
|
|
|
kfree(new);
|
|
|
|
if (IS_ERR(opt))
|
|
|
|
return PTR_ERR(opt);
|
|
|
|
|
|
|
|
/* routing header option needs extra check */
|
|
|
|
err = -EINVAL;
|
|
|
|
if (optname == IPV6_RTHDR && opt && opt->srcrt) {
|
|
|
|
struct ipv6_rt_hdr *rthdr = opt->srcrt;
|
|
|
|
switch (rthdr->type) {
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
|
|
|
case IPV6_SRCRT_TYPE_2:
|
|
|
|
if (rthdr->hdrlen != 2 || rthdr->segments_left != 1)
|
|
|
|
goto sticky_done;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case IPV6_SRCRT_TYPE_4:
|
|
|
|
{
|
|
|
|
struct ipv6_sr_hdr *srh =
|
|
|
|
(struct ipv6_sr_hdr *)opt->srcrt;
|
|
|
|
|
|
|
|
if (!seg6_validate_srh(srh, optlen, false))
|
|
|
|
goto sticky_done;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
goto sticky_done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
opt = ipv6_update_options(sk, opt);
|
|
|
|
sticky_done:
|
|
|
|
if (opt) {
|
|
|
|
atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
|
|
|
|
txopt_put(opt);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-08-17 14:18:34 +08:00
|
|
|
int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
|
|
|
sockptr_t optval, unsigned int optlen)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
2008-03-26 01:26:21 +08:00
|
|
|
struct net *net = sock_net(sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
int val, valbool;
|
|
|
|
int retv = -ENOPROTOOPT;
|
2015-03-19 01:50:42 +08:00
|
|
|
bool needs_rtnl = setsockopt_needs_rtnl(optname);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2020-07-23 14:09:03 +08:00
|
|
|
if (sockptr_is_null(optval))
|
2014-08-25 04:53:10 +08:00
|
|
|
val = 0;
|
2008-04-12 11:59:42 +08:00
|
|
|
else {
|
|
|
|
if (optlen >= sizeof(int)) {
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(&val, optval, sizeof(val)))
|
2008-04-12 11:59:42 +08:00
|
|
|
return -EFAULT;
|
|
|
|
} else
|
|
|
|
val = 0;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-08-25 04:53:10 +08:00
|
|
|
valbool = (val != 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-04-03 08:22:53 +08:00
|
|
|
if (ip6_mroute_opt(optname))
|
2020-07-23 14:09:03 +08:00
|
|
|
return ip6_mroute_setsockopt(sk, optname, optval, optlen);
|
2008-04-03 08:22:53 +08:00
|
|
|
|
2023-09-13 00:01:59 +08:00
|
|
|
/* Handle options that can be set without locking the socket. */
|
|
|
|
switch (optname) {
|
|
|
|
case IPV6_UNICAST_HOPS:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
if (val > 255 || val < -1)
|
|
|
|
return -EINVAL;
|
|
|
|
WRITE_ONCE(np->hop_limit, val);
|
|
|
|
return 0;
|
2023-09-13 00:02:00 +08:00
|
|
|
case IPV6_MULTICAST_LOOP:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
if (val != valbool)
|
|
|
|
return -EINVAL;
|
|
|
|
inet6_assign_bit(MC6_LOOP, sk, valbool);
|
|
|
|
return 0;
|
2023-09-13 00:02:01 +08:00
|
|
|
case IPV6_MULTICAST_HOPS:
|
|
|
|
if (sk->sk_type == SOCK_STREAM)
|
|
|
|
return retv;
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
if (val > 255 || val < -1)
|
|
|
|
return -EINVAL;
|
|
|
|
WRITE_ONCE(np->mcast_hops,
|
|
|
|
val == -1 ? IPV6_DEFAULT_MCASTHOPS : val);
|
|
|
|
return 0;
|
2023-09-13 00:02:02 +08:00
|
|
|
case IPV6_MTU:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
if (val && val < IPV6_MIN_MTU)
|
|
|
|
return -EINVAL;
|
|
|
|
WRITE_ONCE(np->frag_size, val);
|
|
|
|
return 0;
|
2023-09-13 00:02:03 +08:00
|
|
|
case IPV6_MINHOPCOUNT:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
if (val < 0 || val > 255)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (val)
|
|
|
|
static_branch_enable(&ip6_min_hopcount);
|
|
|
|
|
|
|
|
/* tcp_v6_err() and tcp_v6_rcv() might read min_hopcount
|
|
|
|
* while we are changing it.
|
|
|
|
*/
|
|
|
|
WRITE_ONCE(np->min_hopcount, val);
|
|
|
|
return 0;
|
2023-09-13 00:02:04 +08:00
|
|
|
case IPV6_RECVERR_RFC4884:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
if (val < 0 || val > 1)
|
|
|
|
return -EINVAL;
|
|
|
|
inet6_assign_bit(RECVERR6_RFC4884, sk, valbool);
|
|
|
|
return 0;
|
2023-09-13 00:02:05 +08:00
|
|
|
case IPV6_MULTICAST_ALL:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
inet6_assign_bit(MC6_ALL, sk, valbool);
|
|
|
|
return 0;
|
2023-09-13 00:02:06 +08:00
|
|
|
case IPV6_AUTOFLOWLABEL:
|
|
|
|
inet6_assign_bit(AUTOFLOWLABEL, sk, valbool);
|
|
|
|
inet6_set_bit(AUTOFLOWLABEL_SET, sk);
|
|
|
|
return 0;
|
2023-09-13 00:02:07 +08:00
|
|
|
case IPV6_DONTFRAG:
|
|
|
|
inet6_assign_bit(DONTFRAG, sk, valbool);
|
|
|
|
return 0;
|
2023-09-13 00:02:08 +08:00
|
|
|
case IPV6_RECVERR:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
inet6_assign_bit(RECVERR6, sk, valbool);
|
|
|
|
if (!val)
|
|
|
|
skb_errqueue_purge(&sk->sk_error_queue);
|
|
|
|
return 0;
|
2023-09-13 00:02:10 +08:00
|
|
|
case IPV6_ROUTER_ALERT_ISOLATE:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
inet6_assign_bit(RTALERT_ISOLATE, sk, valbool);
|
|
|
|
return 0;
|
2023-09-13 00:02:11 +08:00
|
|
|
case IPV6_MTU_DISCOVER:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT)
|
|
|
|
return -EINVAL;
|
|
|
|
WRITE_ONCE(np->pmtudisc, val);
|
|
|
|
return 0;
|
2023-09-13 00:02:12 +08:00
|
|
|
case IPV6_FLOWINFO_SEND:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
inet6_assign_bit(SNDFLOW, sk, valbool);
|
|
|
|
return 0;
|
2023-09-18 22:23:21 +08:00
|
|
|
case IPV6_ADDR_PREFERENCES:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
return ip6_sock_set_addr_preferences(sk, val);
|
2023-12-08 18:12:43 +08:00
|
|
|
case IPV6_MULTICAST_IF:
|
|
|
|
if (sk->sk_type == SOCK_STREAM)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
if (val) {
|
|
|
|
struct net_device *dev;
|
|
|
|
int bound_dev_if, midx;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
dev = dev_get_by_index_rcu(net, val);
|
|
|
|
if (!dev) {
|
|
|
|
rcu_read_unlock();
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
midx = l3mdev_master_ifindex_rcu(dev);
|
|
|
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
|
|
|
|
if (bound_dev_if &&
|
|
|
|
bound_dev_if != val &&
|
|
|
|
(!midx || midx != bound_dev_if))
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
WRITE_ONCE(np->mcast_oif, val);
|
|
|
|
return 0;
|
2023-12-08 18:12:44 +08:00
|
|
|
case IPV6_UNICAST_IF:
|
|
|
|
{
|
|
|
|
struct net_device *dev;
|
|
|
|
int ifindex;
|
|
|
|
|
|
|
|
if (optlen != sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
ifindex = (__force int)ntohl((__force __be32)val);
|
|
|
|
if (!ifindex) {
|
|
|
|
WRITE_ONCE(np->ucast_oif, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = dev_get_by_index(net, ifindex);
|
|
|
|
if (!dev)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
dev_put(dev);
|
|
|
|
|
|
|
|
if (READ_ONCE(sk->sk_bound_dev_if))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
WRITE_ONCE(np->ucast_oif, ifindex);
|
|
|
|
return 0;
|
|
|
|
}
|
2023-09-13 00:01:59 +08:00
|
|
|
}
|
2015-03-19 01:50:42 +08:00
|
|
|
if (needs_rtnl)
|
|
|
|
rtnl_lock();
|
2022-08-17 14:17:44 +08:00
|
|
|
sockopt_lock_sock(sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
tcp/udp: Fix memory leak in ipv6_renew_options().
syzbot reported a memory leak [0] related to IPV6_ADDRFORM.
The scenario is that while one thread is converting an IPv6 socket into
IPv4 with IPV6_ADDRFORM, another thread calls do_ipv6_setsockopt() and
allocates memory to inet6_sk(sk)->XXX after conversion.
Then, the converted sk with (tcp|udp)_prot never frees the IPv6 resources,
which inet6_destroy_sock() should have cleaned up.
setsockopt(IPV6_ADDRFORM) setsockopt(IPV6_DSTOPTS)
+-----------------------+ +----------------------+
- do_ipv6_setsockopt(sk, ...)
- sockopt_lock_sock(sk) - do_ipv6_setsockopt(sk, ...)
- lock_sock(sk) ^._ called via tcpv6_prot
- WRITE_ONCE(sk->sk_prot, &tcp_prot) before WRITE_ONCE()
- xchg(&np->opt, NULL)
- txopt_put(opt)
- sockopt_release_sock(sk)
- release_sock(sk) - sockopt_lock_sock(sk)
- lock_sock(sk)
- ipv6_set_opt_hdr(sk, ...)
- ipv6_update_options(sk, opt)
- xchg(&inet6_sk(sk)->opt, opt)
^._ opt is never freed.
- sockopt_release_sock(sk)
- release_sock(sk)
Since IPV6_DSTOPTS allocates options under lock_sock(), we can avoid this
memory leak by testing whether sk_family is changed by IPV6_ADDRFORM after
acquiring the lock.
This issue exists from the initial commit between IPV6_ADDRFORM and
IPV6_PKTOPTIONS.
[0]:
BUG: memory leak
unreferenced object 0xffff888009ab9f80 (size 96):
comm "syz-executor583", pid 328, jiffies 4294916198 (age 13.034s)
hex dump (first 32 bytes):
01 00 00 00 48 00 00 00 08 00 00 00 00 00 00 00 ....H...........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<000000002ee98ae1>] kmalloc include/linux/slab.h:605 [inline]
[<000000002ee98ae1>] sock_kmalloc+0xb3/0x100 net/core/sock.c:2566
[<0000000065d7b698>] ipv6_renew_options+0x21e/0x10b0 net/ipv6/exthdrs.c:1318
[<00000000a8c756d7>] ipv6_set_opt_hdr net/ipv6/ipv6_sockglue.c:354 [inline]
[<00000000a8c756d7>] do_ipv6_setsockopt.constprop.0+0x28b7/0x4350 net/ipv6/ipv6_sockglue.c:668
[<000000002854d204>] ipv6_setsockopt+0xdf/0x190 net/ipv6/ipv6_sockglue.c:1021
[<00000000e69fdcf8>] tcp_setsockopt+0x13b/0x2620 net/ipv4/tcp.c:3789
[<0000000090da4b9b>] __sys_setsockopt+0x239/0x620 net/socket.c:2252
[<00000000b10d192f>] __do_sys_setsockopt net/socket.c:2263 [inline]
[<00000000b10d192f>] __se_sys_setsockopt net/socket.c:2260 [inline]
[<00000000b10d192f>] __x64_sys_setsockopt+0xbe/0x160 net/socket.c:2260
[<000000000a80d7aa>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
[<000000000a80d7aa>] do_syscall_64+0x38/0x90 arch/x86/entry/common.c:80
[<000000004562b5c6>] entry_SYSCALL_64_after_hwframe+0x63/0xcd
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-10-07 02:53:45 +08:00
|
|
|
/* Another thread has converted the socket into IPv4 with
|
|
|
|
* IPV6_ADDRFORM concurrently.
|
|
|
|
*/
|
|
|
|
if (unlikely(sk->sk_family != AF_INET6))
|
|
|
|
goto unlock;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
switch (optname) {
|
|
|
|
|
|
|
|
case IPV6_ADDRFORM:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (val == PF_INET) {
|
2008-06-04 19:49:06 +08:00
|
|
|
if (sk->sk_type == SOCK_RAW)
|
|
|
|
break;
|
|
|
|
|
2008-06-04 19:49:08 +08:00
|
|
|
if (sk->sk_protocol == IPPROTO_UDP ||
|
|
|
|
sk->sk_protocol == IPPROTO_UDPLITE) {
|
|
|
|
struct udp_sock *up = udp_sk(sk);
|
|
|
|
if (up->pending == AF_INET6) {
|
|
|
|
retv = -EBUSY;
|
|
|
|
break;
|
|
|
|
}
|
2020-06-01 11:55:03 +08:00
|
|
|
} else if (sk->sk_protocol == IPPROTO_TCP) {
|
|
|
|
if (sk->sk_prot != &tcpv6_prot) {
|
|
|
|
retv = -EBUSY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2020-02-26 03:52:29 +08:00
|
|
|
break;
|
|
|
|
}
|
2020-06-01 11:55:03 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (sk->sk_state != TCP_ESTABLISHED) {
|
|
|
|
retv = -ENOTCONN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipv6_only_sock(sk) ||
|
ipv6: make lookups simpler and faster
TCP listener refactoring, part 4 :
To speed up inet lookups, we moved IPv4 addresses from inet to struct
sock_common
Now is time to do the same for IPv6, because it permits us to have fast
lookups for all kind of sockets, including upcoming SYN_RECV.
Getting IPv6 addresses in TCP lookups currently requires two extra cache
lines, plus a dereference (and memory stall).
inet6_sk(sk) does the dereference of inet_sk(__sk)->pinet6
This patch is way bigger than its IPv4 counter part, because for IPv4,
we could add aliases (inet_daddr, inet_rcv_saddr), while on IPv6,
it's not doable easily.
inet6_sk(sk)->daddr becomes sk->sk_v6_daddr
inet6_sk(sk)->rcv_saddr becomes sk->sk_v6_rcv_saddr
And timewait socket also have tw->tw_v6_daddr & tw->tw_v6_rcv_saddr
at the same offset.
We get rid of INET6_TW_MATCH() as INET6_MATCH() is now the generic
macro.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-10-04 06:42:29 +08:00
|
|
|
!ipv6_addr_v4mapped(&sk->sk_v6_daddr)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
retv = -EADDRNOTAVAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-10-20 14:35:12 +08:00
|
|
|
__ipv6_sock_mc_close(sk);
|
ipv6: fix memory leaks on IPV6_ADDRFORM path
IPV6_ADDRFORM causes resource leaks when converting an IPv6 socket
to IPv4, particularly struct ipv6_ac_socklist. Similar to
struct ipv6_mc_socklist, we should just close it on this path.
This bug can be easily reproduced with the following C program:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main()
{
int s, value;
struct sockaddr_in6 addr;
struct ipv6_mreq m6;
s = socket(AF_INET6, SOCK_DGRAM, 0);
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(5000);
inet_pton(AF_INET6, "::ffff:192.168.122.194", &addr.sin6_addr);
connect(s, (struct sockaddr *)&addr, sizeof(addr));
inet_pton(AF_INET6, "fe80::AAAA", &m6.ipv6mr_multiaddr);
m6.ipv6mr_interface = 5;
setsockopt(s, SOL_IPV6, IPV6_JOIN_ANYCAST, &m6, sizeof(m6));
value = AF_INET;
setsockopt(s, SOL_IPV6, IPV6_ADDRFORM, &value, sizeof(value));
close(s);
return 0;
}
Reported-by: ch3332xr@gmail.com
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2020-07-26 06:40:53 +08:00
|
|
|
__ipv6_sock_ac_close(sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (sk->sk_protocol == IPPROTO_TCP) {
|
2005-12-14 15:26:10 +08:00
|
|
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
2021-11-16 01:11:50 +08:00
|
|
|
|
2008-04-01 10:41:46 +08:00
|
|
|
sock_prot_inuse_add(net, sk->sk_prot, -1);
|
|
|
|
sock_prot_inuse_add(net, &tcp_prot, 1);
|
2021-11-16 01:11:50 +08:00
|
|
|
|
2022-10-07 02:53:48 +08:00
|
|
|
/* Paired with READ_ONCE(sk->sk_prot) in inet6_stream_ops */
|
2022-02-18 07:48:41 +08:00
|
|
|
WRITE_ONCE(sk->sk_prot, &tcp_prot);
|
2022-10-07 02:53:49 +08:00
|
|
|
/* Paired with READ_ONCE() in tcp_(get|set)sockopt() */
|
|
|
|
WRITE_ONCE(icsk->icsk_af_ops, &ipv4_specific);
|
2023-08-08 21:58:09 +08:00
|
|
|
WRITE_ONCE(sk->sk_socket->ops, &inet_stream_ops);
|
|
|
|
WRITE_ONCE(sk->sk_family, PF_INET);
|
2005-12-14 15:26:10 +08:00
|
|
|
tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
2006-11-28 03:10:57 +08:00
|
|
|
struct proto *prot = &udp_prot;
|
|
|
|
|
2008-03-07 08:22:02 +08:00
|
|
|
if (sk->sk_protocol == IPPROTO_UDPLITE)
|
2006-11-28 03:10:57 +08:00
|
|
|
prot = &udplite_prot;
|
2021-11-16 01:11:50 +08:00
|
|
|
|
2008-04-01 10:41:46 +08:00
|
|
|
sock_prot_inuse_add(net, sk->sk_prot, -1);
|
|
|
|
sock_prot_inuse_add(net, prot, 1);
|
2021-11-16 01:11:50 +08:00
|
|
|
|
2022-10-07 02:53:48 +08:00
|
|
|
/* Paired with READ_ONCE(sk->sk_prot) in inet6_dgram_ops */
|
2022-02-18 07:48:41 +08:00
|
|
|
WRITE_ONCE(sk->sk_prot, prot);
|
2023-08-08 21:58:09 +08:00
|
|
|
WRITE_ONCE(sk->sk_socket->ops, &inet_dgram_ops);
|
|
|
|
WRITE_ONCE(sk->sk_family, PF_INET);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2022-10-07 02:53:46 +08:00
|
|
|
|
|
|
|
/* Disable all options not to allocate memory anymore,
|
|
|
|
* but there is still a race. See the lockless path
|
|
|
|
* in udpv6_sendmsg() and ipv6_local_rxpmtu().
|
|
|
|
*/
|
|
|
|
np->rxopt.all = 0;
|
|
|
|
|
|
|
|
inet6_cleanup_sock(sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
module_put(THIS_MODULE);
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
case IPV6_V6ONLY:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int) ||
|
2009-10-15 14:30:45 +08:00
|
|
|
inet_sk(sk)->inet_num)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto e_inval;
|
2014-06-27 23:36:16 +08:00
|
|
|
sk->sk_ipv6only = valbool;
|
2005-04-17 06:20:36 +08:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_RECVPKTINFO:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-17 06:20:36 +08:00
|
|
|
np->rxopt.bits.rxinfo = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2007-02-09 22:24:49 +08:00
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292PKTINFO:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
np->rxopt.bits.rxoinfo = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_RECVHOPLIMIT:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-17 06:20:36 +08:00
|
|
|
np->rxopt.bits.rxhlim = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292HOPLIMIT:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
np->rxopt.bits.rxohlim = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVRTHDR:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2007-05-23 12:28:48 +08:00
|
|
|
np->rxopt.bits.srcrt = valbool;
|
2005-04-17 06:20:36 +08:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292RTHDR:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2007-05-23 12:28:48 +08:00
|
|
|
np->rxopt.bits.osrcrt = valbool;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVHOPOPTS:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-17 06:20:36 +08:00
|
|
|
np->rxopt.bits.hopopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292HOPOPTS:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
np->rxopt.bits.ohopopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVDSTOPTS:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-17 06:20:36 +08:00
|
|
|
np->rxopt.bits.dstopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292DSTOPTS:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
np->rxopt.bits.odstopts = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2005-09-08 09:19:03 +08:00
|
|
|
case IPV6_TCLASS:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2006-09-14 11:08:07 +08:00
|
|
|
if (val < -1 || val > 0xff)
|
2005-09-08 09:19:03 +08:00
|
|
|
goto e_inval;
|
inet6: Set default traffic class
This patch addresses:
* assigning -1 to np->tclass as it is currently done is not very meaningful,
since it turns into 0xff;
* RFC 3542, 6.5 allows -1 for clearing the sticky IPV6_TCLASS option
and specifies -1 to mean "use kernel default":
- RFC 2460, 7. requires that the default traffic class must be zero for
all 8 bits,
- this is consistent with RFC 2474, 4.1 which recommends a default PHB of 0,
in combination with a value of the ECN field of "non-ECT" (RFC 3168, 5.).
This patch changes the meaning of -1 from assigning 255 to mean the RFC 2460
default, which at the same time allows to satisfy clearing the sticky TCLASS
option as per RFC 3542, 6.5.
(When passing -1 as ancillary data, the fallback remains np->tclass, which
has either been set via socket options, or contains the default value.)
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-08-09 16:12:49 +08:00
|
|
|
/* RFC 3542, 6.5: default traffic class of 0x0 */
|
|
|
|
if (val == -1)
|
|
|
|
val = 0;
|
2021-11-24 06:31:54 +08:00
|
|
|
if (sk->sk_type == SOCK_STREAM) {
|
|
|
|
val &= ~INET_ECN_MASK;
|
|
|
|
val |= np->tclass & INET_ECN_MASK;
|
|
|
|
}
|
2021-11-24 06:32:08 +08:00
|
|
|
if (np->tclass != val) {
|
|
|
|
np->tclass = val;
|
|
|
|
sk_dst_reset(sk);
|
|
|
|
}
|
2005-09-08 09:19:03 +08:00
|
|
|
retv = 0;
|
|
|
|
break;
|
2007-02-09 22:24:49 +08:00
|
|
|
|
2005-09-08 09:19:03 +08:00
|
|
|
case IPV6_RECVTCLASS:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-09-08 09:19:03 +08:00
|
|
|
np->rxopt.bits.rxtclass = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case IPV6_FLOWINFO:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2005-04-17 06:20:36 +08:00
|
|
|
np->rxopt.bits.rxflow = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2010-04-23 19:26:07 +08:00
|
|
|
case IPV6_RECVPATHMTU:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
np->rxopt.bits.rxpmtu = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2010-10-21 22:08:28 +08:00
|
|
|
case IPV6_TRANSPARENT:
|
2022-08-17 14:17:44 +08:00
|
|
|
if (valbool && !sockopt_ns_capable(net->user_ns, CAP_NET_RAW) &&
|
|
|
|
!sockopt_ns_capable(net->user_ns, CAP_NET_ADMIN)) {
|
2010-10-23 12:48:14 +08:00
|
|
|
retv = -EPERM;
|
|
|
|
break;
|
|
|
|
}
|
2010-10-21 22:08:28 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
/* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */
|
2023-08-16 16:15:41 +08:00
|
|
|
inet_assign_bit(TRANSPARENT, sk, valbool);
|
2010-10-21 22:08:28 +08:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
net-ipv6: add support for sockopt(SOL_IPV6, IPV6_FREEBIND)
So far we've been relying on sockopt(SOL_IP, IP_FREEBIND) being usable
even on IPv6 sockets.
However, it turns out it is perfectly reasonable to want to set freebind
on an AF_INET6 SOCK_RAW socket - but there is no way to set any SOL_IP
socket option on such a socket (they're all blindly errored out).
One use case for this is to allow spoofing src ip on a raw socket
via sendmsg cmsg.
Tested:
built, and booted
# python
>>> import socket
>>> SOL_IP = socket.SOL_IP
>>> SOL_IPV6 = socket.IPPROTO_IPV6
>>> IP_FREEBIND = 15
>>> IPV6_FREEBIND = 78
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
0
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
0
>>> s.setsockopt(SOL_IPV6, IPV6_FREEBIND, 1)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
1
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
1
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-27 12:32:42 +08:00
|
|
|
case IPV6_FREEBIND:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
/* we also don't have a separate freebind bit for IPV6 */
|
2023-08-16 16:15:37 +08:00
|
|
|
inet_assign_bit(FREEBIND, sk, valbool);
|
net-ipv6: add support for sockopt(SOL_IPV6, IPV6_FREEBIND)
So far we've been relying on sockopt(SOL_IP, IP_FREEBIND) being usable
even on IPv6 sockets.
However, it turns out it is perfectly reasonable to want to set freebind
on an AF_INET6 SOCK_RAW socket - but there is no way to set any SOL_IP
socket option on such a socket (they're all blindly errored out).
One use case for this is to allow spoofing src ip on a raw socket
via sendmsg cmsg.
Tested:
built, and booted
# python
>>> import socket
>>> SOL_IP = socket.SOL_IP
>>> SOL_IPV6 = socket.IPPROTO_IPV6
>>> IP_FREEBIND = 15
>>> IPV6_FREEBIND = 78
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
0
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
0
>>> s.setsockopt(SOL_IPV6, IPV6_FREEBIND, 1)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
1
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
1
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-27 12:32:42 +08:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
2010-10-21 22:08:28 +08:00
|
|
|
case IPV6_RECVORIGDSTADDR:
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
|
|
|
np->rxopt.bits.rxorigdstaddr = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
case IPV6_DSTOPTS:
|
2020-07-23 14:09:02 +08:00
|
|
|
retv = ipv6_set_opt_hdr(sk, optname, optval, optlen);
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
break;
|
|
|
|
|
2008-12-16 18:06:23 +08:00
|
|
|
case IPV6_PKTINFO:
|
|
|
|
{
|
|
|
|
struct in6_pktinfo pkt;
|
|
|
|
|
|
|
|
if (optlen == 0)
|
|
|
|
goto e_inval;
|
2020-07-23 14:09:03 +08:00
|
|
|
else if (optlen < sizeof(struct in6_pktinfo) ||
|
|
|
|
sockptr_is_null(optval))
|
2008-12-16 18:06:23 +08:00
|
|
|
goto e_inval;
|
|
|
|
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(&pkt, optval, sizeof(pkt))) {
|
|
|
|
retv = -EFAULT;
|
|
|
|
break;
|
2008-12-16 18:06:23 +08:00
|
|
|
}
|
2018-11-07 23:36:08 +08:00
|
|
|
if (!sk_dev_equal_l3scope(sk, pkt.ipi6_ifindex))
|
2008-12-16 18:06:23 +08:00
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex;
|
2011-11-21 11:39:03 +08:00
|
|
|
np->sticky_pktinfo.ipi6_addr = pkt.ipi6_addr;
|
2008-12-16 18:06:23 +08:00
|
|
|
retv = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292PKTOPTIONS:
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct ipv6_txoptions *opt = NULL;
|
|
|
|
struct msghdr msg;
|
2011-03-13 05:22:43 +08:00
|
|
|
struct flowi6 fl6;
|
2016-05-03 12:40:07 +08:00
|
|
|
struct ipcm6_cookie ipc6;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2011-03-13 05:22:43 +08:00
|
|
|
memset(&fl6, 0, sizeof(fl6));
|
|
|
|
fl6.flowi6_oif = sk->sk_bound_dev_if;
|
|
|
|
fl6.flowi6_mark = sk->sk_mark;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (optlen == 0)
|
|
|
|
goto update;
|
|
|
|
|
|
|
|
/* 1K is probably excessive
|
|
|
|
* 1K is surely not enough, 2K per standard header is 16K.
|
|
|
|
*/
|
|
|
|
retv = -EINVAL;
|
|
|
|
if (optlen > 64*1024)
|
|
|
|
break;
|
|
|
|
|
|
|
|
opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
|
|
|
|
retv = -ENOBUFS;
|
2015-03-29 21:00:04 +08:00
|
|
|
if (!opt)
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
memset(opt, 0, sizeof(*opt));
|
2017-07-04 14:34:54 +08:00
|
|
|
refcount_set(&opt->refcnt, 1);
|
2005-04-17 06:20:36 +08:00
|
|
|
opt->tot_len = sizeof(*opt) + optlen;
|
|
|
|
retv = -EFAULT;
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(opt + 1, optval, optlen))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
msg.msg_controllen = optlen;
|
2023-04-13 19:47:05 +08:00
|
|
|
msg.msg_control_is_user = false;
|
2014-08-25 04:53:10 +08:00
|
|
|
msg.msg_control = (void *)(opt+1);
|
2016-05-03 12:40:07 +08:00
|
|
|
ipc6.opt = opt;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2018-07-06 22:12:57 +08:00
|
|
|
retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, &ipc6);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (retv)
|
|
|
|
goto done;
|
|
|
|
update:
|
|
|
|
retv = 0;
|
2008-04-14 14:21:52 +08:00
|
|
|
opt = ipv6_update_options(sk, opt);
|
2005-04-17 06:20:36 +08:00
|
|
|
done:
|
2015-11-30 11:37:57 +08:00
|
|
|
if (opt) {
|
|
|
|
atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
|
|
|
|
txopt_put(opt);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_ADD_MEMBERSHIP:
|
|
|
|
case IPV6_DROP_MEMBERSHIP:
|
|
|
|
{
|
|
|
|
struct ipv6_mreq mreq;
|
|
|
|
|
2008-04-07 09:42:07 +08:00
|
|
|
if (optlen < sizeof(struct ipv6_mreq))
|
|
|
|
goto e_inval;
|
|
|
|
|
2007-08-25 13:16:39 +08:00
|
|
|
retv = -EPROTO;
|
2023-08-16 16:15:42 +08:00
|
|
|
if (inet_test_bit(IS_ICSK, sk))
|
2007-08-25 13:16:39 +08:00
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
retv = -EFAULT;
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(&mreq, optval, sizeof(struct ipv6_mreq)))
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (optname == IPV6_ADD_MEMBERSHIP)
|
ipv4, ipv6: kill ip_mc_{join, leave}_group and ipv6_sock_mc_{join, drop}
in favor of their inner __ ones, which doesn't grab rtnl.
As these functions need to operate on a locked socket, we can't be
grabbing rtnl by then. It's too late and doing so causes reversed
locking.
So this patch:
- move rtnl handling to callers instead while already fixing some
reversed locking situations, like on vxlan and ipvs code.
- renames __ ones to not have the __ mark:
__ip_mc_{join,leave}_group -> ip_mc_{join,leave}_group
__ipv6_sock_mc_{join,drop} -> ipv6_sock_mc_{join,drop}
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-19 01:50:43 +08:00
|
|
|
retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
|
2005-04-17 06:20:36 +08:00
|
|
|
else
|
ipv4, ipv6: kill ip_mc_{join, leave}_group and ipv6_sock_mc_{join, drop}
in favor of their inner __ ones, which doesn't grab rtnl.
As these functions need to operate on a locked socket, we can't be
grabbing rtnl by then. It's too late and doing so causes reversed
locking.
So this patch:
- move rtnl handling to callers instead while already fixing some
reversed locking situations, like on vxlan and ipvs code.
- renames __ ones to not have the __ mark:
__ip_mc_{join,leave}_group -> ip_mc_{join,leave}_group
__ipv6_sock_mc_{join,drop} -> ipv6_sock_mc_{join,drop}
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2015-03-19 01:50:43 +08:00
|
|
|
retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IPV6_JOIN_ANYCAST:
|
|
|
|
case IPV6_LEAVE_ANYCAST:
|
|
|
|
{
|
|
|
|
struct ipv6_mreq mreq;
|
|
|
|
|
2008-04-07 09:42:07 +08:00
|
|
|
if (optlen < sizeof(struct ipv6_mreq))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto e_inval;
|
|
|
|
|
|
|
|
retv = -EFAULT;
|
2020-07-23 14:09:03 +08:00
|
|
|
if (copy_from_sockptr(&mreq, optval, sizeof(struct ipv6_mreq)))
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (optname == IPV6_JOIN_ANYCAST)
|
|
|
|
retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
|
|
|
|
else
|
|
|
|
retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MCAST_JOIN_GROUP:
|
|
|
|
case MCAST_LEAVE_GROUP:
|
2020-07-17 14:23:30 +08:00
|
|
|
if (in_compat_syscall())
|
|
|
|
retv = compat_ipv6_mcast_join_leave(sk, optname, optval,
|
|
|
|
optlen);
|
|
|
|
else
|
|
|
|
retv = ipv6_mcast_join_leave(sk, optname, optval,
|
|
|
|
optlen);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
case MCAST_JOIN_SOURCE_GROUP:
|
|
|
|
case MCAST_LEAVE_SOURCE_GROUP:
|
|
|
|
case MCAST_BLOCK_SOURCE:
|
|
|
|
case MCAST_UNBLOCK_SOURCE:
|
2020-07-17 14:23:30 +08:00
|
|
|
retv = do_ipv6_mcast_group_source(sk, optname, optval, optlen);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
case MCAST_MSFILTER:
|
2020-07-17 14:23:30 +08:00
|
|
|
if (in_compat_syscall())
|
|
|
|
retv = compat_ipv6_set_mcast_msfilter(sk, optval,
|
|
|
|
optlen);
|
|
|
|
else
|
|
|
|
retv = ipv6_set_mcast_msfilter(sk, optval, optlen);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
case IPV6_ROUTER_ALERT:
|
2008-04-12 11:59:42 +08:00
|
|
|
if (optlen < sizeof(int))
|
|
|
|
goto e_inval;
|
2008-07-19 15:28:58 +08:00
|
|
|
retv = ip6_ra_control(sk, val);
|
2024-03-04 19:32:08 +08:00
|
|
|
if (retv == 0)
|
|
|
|
inet6_assign_bit(RTALERT, sk, valbool);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
case IPV6_FLOWLABEL_MGR:
|
2020-07-23 14:09:03 +08:00
|
|
|
retv = ipv6_flowlabel_opt(sk, optval, optlen);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
case IPV6_IPSEC_POLICY:
|
|
|
|
case IPV6_XFRM_POLICY:
|
2005-08-06 21:33:15 +08:00
|
|
|
retv = -EPERM;
|
2022-08-17 14:17:44 +08:00
|
|
|
if (!sockopt_ns_capable(net->user_ns, CAP_NET_ADMIN))
|
2005-08-06 21:33:15 +08:00
|
|
|
break;
|
2020-07-23 14:09:03 +08:00
|
|
|
retv = xfrm_user_policy(sk, optname, optval, optlen);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2016-11-02 23:02:17 +08:00
|
|
|
case IPV6_RECVFRAGSIZE:
|
|
|
|
np->rxopt.bits.recvfragsize = valbool;
|
|
|
|
retv = 0;
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2008-03-25 08:37:42 +08:00
|
|
|
|
tcp/udp: Fix memory leak in ipv6_renew_options().
syzbot reported a memory leak [0] related to IPV6_ADDRFORM.
The scenario is that while one thread is converting an IPv6 socket into
IPv4 with IPV6_ADDRFORM, another thread calls do_ipv6_setsockopt() and
allocates memory to inet6_sk(sk)->XXX after conversion.
Then, the converted sk with (tcp|udp)_prot never frees the IPv6 resources,
which inet6_destroy_sock() should have cleaned up.
setsockopt(IPV6_ADDRFORM) setsockopt(IPV6_DSTOPTS)
+-----------------------+ +----------------------+
- do_ipv6_setsockopt(sk, ...)
- sockopt_lock_sock(sk) - do_ipv6_setsockopt(sk, ...)
- lock_sock(sk) ^._ called via tcpv6_prot
- WRITE_ONCE(sk->sk_prot, &tcp_prot) before WRITE_ONCE()
- xchg(&np->opt, NULL)
- txopt_put(opt)
- sockopt_release_sock(sk)
- release_sock(sk) - sockopt_lock_sock(sk)
- lock_sock(sk)
- ipv6_set_opt_hdr(sk, ...)
- ipv6_update_options(sk, opt)
- xchg(&inet6_sk(sk)->opt, opt)
^._ opt is never freed.
- sockopt_release_sock(sk)
- release_sock(sk)
Since IPV6_DSTOPTS allocates options under lock_sock(), we can avoid this
memory leak by testing whether sk_family is changed by IPV6_ADDRFORM after
acquiring the lock.
This issue exists from the initial commit between IPV6_ADDRFORM and
IPV6_PKTOPTIONS.
[0]:
BUG: memory leak
unreferenced object 0xffff888009ab9f80 (size 96):
comm "syz-executor583", pid 328, jiffies 4294916198 (age 13.034s)
hex dump (first 32 bytes):
01 00 00 00 48 00 00 00 08 00 00 00 00 00 00 00 ....H...........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace:
[<000000002ee98ae1>] kmalloc include/linux/slab.h:605 [inline]
[<000000002ee98ae1>] sock_kmalloc+0xb3/0x100 net/core/sock.c:2566
[<0000000065d7b698>] ipv6_renew_options+0x21e/0x10b0 net/ipv6/exthdrs.c:1318
[<00000000a8c756d7>] ipv6_set_opt_hdr net/ipv6/ipv6_sockglue.c:354 [inline]
[<00000000a8c756d7>] do_ipv6_setsockopt.constprop.0+0x28b7/0x4350 net/ipv6/ipv6_sockglue.c:668
[<000000002854d204>] ipv6_setsockopt+0xdf/0x190 net/ipv6/ipv6_sockglue.c:1021
[<00000000e69fdcf8>] tcp_setsockopt+0x13b/0x2620 net/ipv4/tcp.c:3789
[<0000000090da4b9b>] __sys_setsockopt+0x239/0x620 net/socket.c:2252
[<00000000b10d192f>] __do_sys_setsockopt net/socket.c:2263 [inline]
[<00000000b10d192f>] __se_sys_setsockopt net/socket.c:2260 [inline]
[<00000000b10d192f>] __x64_sys_setsockopt+0xbe/0x160 net/socket.c:2260
[<000000000a80d7aa>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
[<000000000a80d7aa>] do_syscall_64+0x38/0x90 arch/x86/entry/common.c:80
[<000000004562b5c6>] entry_SYSCALL_64_after_hwframe+0x63/0xcd
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2022-10-07 02:53:45 +08:00
|
|
|
unlock:
|
2022-08-17 14:17:44 +08:00
|
|
|
sockopt_release_sock(sk);
|
2015-03-19 01:50:42 +08:00
|
|
|
if (needs_rtnl)
|
|
|
|
rtnl_unlock();
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return retv;
|
|
|
|
|
|
|
|
e_inval:
|
2022-10-20 06:36:03 +08:00
|
|
|
retv = -EINVAL;
|
|
|
|
goto unlock;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2020-07-23 14:09:07 +08:00
|
|
|
int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
|
|
|
|
unsigned int optlen)
|
2006-03-21 14:45:21 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (level == SOL_IP && sk->sk_type != SOCK_RAW)
|
|
|
|
return udp_prot.setsockopt(sk, level, optname, optval, optlen);
|
|
|
|
|
|
|
|
if (level != SOL_IPV6)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
2020-07-23 14:09:07 +08:00
|
|
|
err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
|
2006-03-21 14:45:21 +08:00
|
|
|
#ifdef CONFIG_NETFILTER
|
|
|
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
|
|
|
if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
|
netfilter: on sockopt() acquire sock lock only in the required scope
Syzbot reported several deadlocks in the netfilter area caused by
rtnl lock and socket lock being acquired with a different order on
different code paths, leading to backtraces like the following one:
======================================================
WARNING: possible circular locking dependency detected
4.15.0-rc9+ #212 Not tainted
------------------------------------------------------
syzkaller041579/3682 is trying to acquire lock:
(sk_lock-AF_INET6){+.+.}, at: [<000000008775e4dd>] lock_sock
include/net/sock.h:1463 [inline]
(sk_lock-AF_INET6){+.+.}, at: [<000000008775e4dd>]
do_ipv6_setsockopt.isra.8+0x3c5/0x39d0 net/ipv6/ipv6_sockglue.c:167
but task is already holding lock:
(rtnl_mutex){+.+.}, at: [<000000004342eaa9>] rtnl_lock+0x17/0x20
net/core/rtnetlink.c:74
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (rtnl_mutex){+.+.}:
__mutex_lock_common kernel/locking/mutex.c:756 [inline]
__mutex_lock+0x16f/0x1a80 kernel/locking/mutex.c:893
mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:908
rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74
register_netdevice_notifier+0xad/0x860 net/core/dev.c:1607
tee_tg_check+0x1a0/0x280 net/netfilter/xt_TEE.c:106
xt_check_target+0x22c/0x7d0 net/netfilter/x_tables.c:845
check_target net/ipv6/netfilter/ip6_tables.c:538 [inline]
find_check_entry.isra.7+0x935/0xcf0
net/ipv6/netfilter/ip6_tables.c:580
translate_table+0xf52/0x1690 net/ipv6/netfilter/ip6_tables.c:749
do_replace net/ipv6/netfilter/ip6_tables.c:1165 [inline]
do_ip6t_set_ctl+0x370/0x5f0 net/ipv6/netfilter/ip6_tables.c:1691
nf_sockopt net/netfilter/nf_sockopt.c:106 [inline]
nf_setsockopt+0x67/0xc0 net/netfilter/nf_sockopt.c:115
ipv6_setsockopt+0x115/0x150 net/ipv6/ipv6_sockglue.c:928
udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1422
sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2978
SYSC_setsockopt net/socket.c:1849 [inline]
SyS_setsockopt+0x189/0x360 net/socket.c:1828
entry_SYSCALL_64_fastpath+0x29/0xa0
-> #0 (sk_lock-AF_INET6){+.+.}:
lock_acquire+0x1d5/0x580 kernel/locking/lockdep.c:3914
lock_sock_nested+0xc2/0x110 net/core/sock.c:2780
lock_sock include/net/sock.h:1463 [inline]
do_ipv6_setsockopt.isra.8+0x3c5/0x39d0 net/ipv6/ipv6_sockglue.c:167
ipv6_setsockopt+0xd7/0x150 net/ipv6/ipv6_sockglue.c:922
udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1422
sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2978
SYSC_setsockopt net/socket.c:1849 [inline]
SyS_setsockopt+0x189/0x360 net/socket.c:1828
entry_SYSCALL_64_fastpath+0x29/0xa0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(rtnl_mutex);
lock(sk_lock-AF_INET6);
lock(rtnl_mutex);
lock(sk_lock-AF_INET6);
*** DEADLOCK ***
1 lock held by syzkaller041579/3682:
#0: (rtnl_mutex){+.+.}, at: [<000000004342eaa9>] rtnl_lock+0x17/0x20
net/core/rtnetlink.c:74
The problem, as Florian noted, is that nf_setsockopt() is always
called with the socket held, even if the lock itself is required only
for very tight scopes and only for some operation.
This patch addresses the issues moving the lock_sock() call only
where really needed, namely in ipv*_getorigdst(), so that nf_setsockopt()
does not need anymore to acquire both locks.
Fixes: 22265a5c3c10 ("netfilter: xt_TEE: resolve oif using netdevice notifiers")
Reported-by: syzbot+a4c2dc980ac1af699b36@syzkaller.appspotmail.com
Suggested-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2018-01-31 02:01:40 +08:00
|
|
|
optname != IPV6_XFRM_POLICY)
|
2020-07-23 14:09:07 +08:00
|
|
|
err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen);
|
2006-03-21 14:45:21 +08:00
|
|
|
#endif
|
|
|
|
return err;
|
|
|
|
}
|
2007-02-22 21:05:40 +08:00
|
|
|
EXPORT_SYMBOL(ipv6_setsockopt);
|
2006-03-21 14:45:21 +08:00
|
|
|
|
2007-03-08 04:50:46 +08:00
|
|
|
static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
|
2022-09-02 08:28:53 +08:00
|
|
|
int optname, sockptr_t optval, int len)
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
{
|
2007-03-08 04:50:46 +08:00
|
|
|
struct ipv6_opt_hdr *hdr;
|
|
|
|
|
2007-03-19 08:35:57 +08:00
|
|
|
if (!opt)
|
|
|
|
return 0;
|
|
|
|
|
2014-08-25 04:53:10 +08:00
|
|
|
switch (optname) {
|
2007-03-19 08:35:57 +08:00
|
|
|
case IPV6_HOPOPTS:
|
|
|
|
hdr = opt->hopopt;
|
|
|
|
break;
|
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
hdr = opt->dst0opt;
|
|
|
|
break;
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
hdr = (struct ipv6_opt_hdr *)opt->srcrt;
|
|
|
|
break;
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
hdr = opt->dst1opt;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL; /* should not happen */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hdr)
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
return 0;
|
2007-03-08 04:50:46 +08:00
|
|
|
|
2007-03-10 08:19:17 +08:00
|
|
|
len = min_t(unsigned int, len, ipv6_optlen(hdr));
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_to_sockptr(optval, hdr, len))
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
return -EFAULT;
|
2008-05-28 16:27:28 +08:00
|
|
|
return len;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
}
|
|
|
|
|
2022-09-02 08:28:53 +08:00
|
|
|
static int ipv6_get_msfilter(struct sock *sk, sockptr_t optval,
|
|
|
|
sockptr_t optlen, int len)
|
2020-07-17 14:23:27 +08:00
|
|
|
{
|
2021-08-05 04:45:36 +08:00
|
|
|
const int size0 = offsetof(struct group_filter, gf_slist_flex);
|
2020-07-17 14:23:27 +08:00
|
|
|
struct group_filter gsf;
|
|
|
|
int num;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (len < size0)
|
|
|
|
return -EINVAL;
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_from_sockptr(&gsf, optval, size0))
|
2020-07-17 14:23:27 +08:00
|
|
|
return -EFAULT;
|
|
|
|
if (gsf.gf_group.ss_family != AF_INET6)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
num = gsf.gf_numsrc;
|
2022-09-02 08:28:59 +08:00
|
|
|
sockopt_lock_sock(sk);
|
2022-09-02 08:28:53 +08:00
|
|
|
err = ip6_mc_msfget(sk, &gsf, optval, size0);
|
2020-07-17 14:23:27 +08:00
|
|
|
if (!err) {
|
|
|
|
if (num > gsf.gf_numsrc)
|
|
|
|
num = gsf.gf_numsrc;
|
2022-09-02 08:28:53 +08:00
|
|
|
len = GROUP_FILTER_SIZE(num);
|
|
|
|
if (copy_to_sockptr(optlen, &len, sizeof(int)) ||
|
|
|
|
copy_to_sockptr(optval, &gsf, size0))
|
2020-07-17 14:23:27 +08:00
|
|
|
err = -EFAULT;
|
|
|
|
}
|
2022-09-02 08:28:59 +08:00
|
|
|
sockopt_release_sock(sk);
|
2020-07-17 14:23:27 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-09-02 08:28:53 +08:00
|
|
|
static int compat_ipv6_get_msfilter(struct sock *sk, sockptr_t optval,
|
|
|
|
sockptr_t optlen, int len)
|
2020-07-17 14:23:27 +08:00
|
|
|
{
|
2021-08-05 04:45:36 +08:00
|
|
|
const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
|
2020-07-17 14:23:27 +08:00
|
|
|
struct compat_group_filter gf32;
|
|
|
|
struct group_filter gf;
|
2022-09-02 08:28:46 +08:00
|
|
|
int err;
|
2020-07-17 14:23:27 +08:00
|
|
|
int num;
|
|
|
|
|
|
|
|
if (len < size0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_from_sockptr(&gf32, optval, size0))
|
2020-07-17 14:23:27 +08:00
|
|
|
return -EFAULT;
|
|
|
|
gf.gf_interface = gf32.gf_interface;
|
|
|
|
gf.gf_fmode = gf32.gf_fmode;
|
|
|
|
num = gf.gf_numsrc = gf32.gf_numsrc;
|
|
|
|
gf.gf_group = gf32.gf_group;
|
|
|
|
|
|
|
|
if (gf.gf_group.ss_family != AF_INET6)
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
|
2022-09-02 08:28:59 +08:00
|
|
|
sockopt_lock_sock(sk);
|
2022-09-02 08:28:53 +08:00
|
|
|
err = ip6_mc_msfget(sk, &gf, optval, size0);
|
2022-09-02 08:28:59 +08:00
|
|
|
sockopt_release_sock(sk);
|
2020-07-17 14:23:27 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
if (num > gf.gf_numsrc)
|
|
|
|
num = gf.gf_numsrc;
|
|
|
|
len = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32));
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_to_sockptr(optlen, &len, sizeof(int)) ||
|
|
|
|
copy_to_sockptr_offset(optval, offsetof(struct compat_group_filter, gf_fmode),
|
|
|
|
&gf.gf_fmode, sizeof(gf32.gf_fmode)) ||
|
|
|
|
copy_to_sockptr_offset(optval, offsetof(struct compat_group_filter, gf_numsrc),
|
|
|
|
&gf.gf_numsrc, sizeof(gf32.gf_numsrc)))
|
2020-07-17 14:23:27 +08:00
|
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-09-02 08:29:31 +08:00
|
|
|
int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
|
|
|
sockptr_t optval, sockptr_t optlen)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
|
|
|
int len;
|
|
|
|
int val;
|
|
|
|
|
2008-04-03 08:22:53 +08:00
|
|
|
if (ip6_mroute_opt(optname))
|
|
|
|
return ip6_mroute_getsockopt(sk, optname, optval, optlen);
|
|
|
|
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_from_sockptr(&len, optlen, sizeof(int)))
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EFAULT;
|
|
|
|
switch (optname) {
|
|
|
|
case IPV6_ADDRFORM:
|
|
|
|
if (sk->sk_protocol != IPPROTO_UDP &&
|
2006-11-28 03:10:57 +08:00
|
|
|
sk->sk_protocol != IPPROTO_UDPLITE &&
|
2005-04-17 06:20:36 +08:00
|
|
|
sk->sk_protocol != IPPROTO_TCP)
|
2008-06-12 02:27:26 +08:00
|
|
|
return -ENOPROTOOPT;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (sk->sk_state != TCP_ESTABLISHED)
|
|
|
|
return -ENOTCONN;
|
|
|
|
val = sk->sk_family;
|
|
|
|
break;
|
|
|
|
case MCAST_MSFILTER:
|
2020-07-17 14:23:30 +08:00
|
|
|
if (in_compat_syscall())
|
2022-09-02 08:28:46 +08:00
|
|
|
return compat_ipv6_get_msfilter(sk, optval, optlen, len);
|
2020-07-17 14:23:27 +08:00
|
|
|
return ipv6_get_msfilter(sk, optval, optlen, len);
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292PKTOPTIONS:
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct msghdr msg;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
|
|
|
if (sk->sk_type != SOCK_STREAM)
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
2022-09-02 08:28:53 +08:00
|
|
|
if (optval.is_kernel) {
|
|
|
|
msg.msg_control_is_user = false;
|
|
|
|
msg.msg_control = optval.kernel;
|
|
|
|
} else {
|
|
|
|
msg.msg_control_is_user = true;
|
|
|
|
msg.msg_control_user = optval.user;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
msg.msg_controllen = len;
|
2022-09-02 08:28:40 +08:00
|
|
|
msg.msg_flags = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2022-09-02 08:28:59 +08:00
|
|
|
sockopt_lock_sock(sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
skb = np->pktoptions;
|
|
|
|
if (skb)
|
2014-01-20 10:43:08 +08:00
|
|
|
ip6_datagram_recv_ctl(sk, &msg, skb);
|
2022-09-02 08:28:59 +08:00
|
|
|
sockopt_release_sock(sk);
|
2015-01-21 19:45:42 +08:00
|
|
|
if (!skb) {
|
2005-04-17 06:20:36 +08:00
|
|
|
if (np->rxopt.bits.rxinfo) {
|
2023-12-08 18:12:43 +08:00
|
|
|
int mcast_oif = READ_ONCE(np->mcast_oif);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct in6_pktinfo src_info;
|
2023-12-08 18:12:43 +08:00
|
|
|
|
|
|
|
src_info.ipi6_ifindex = mcast_oif ? :
|
2008-12-16 18:07:45 +08:00
|
|
|
np->sticky_pktinfo.ipi6_ifindex;
|
2023-12-08 18:12:43 +08:00
|
|
|
src_info.ipi6_addr = mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr;
|
2005-04-17 06:20:36 +08:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
|
|
|
|
}
|
|
|
|
if (np->rxopt.bits.rxhlim) {
|
2023-09-13 00:02:01 +08:00
|
|
|
int hlim = READ_ONCE(np->mcast_hops);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
|
|
|
|
}
|
2012-02-09 17:35:49 +08:00
|
|
|
if (np->rxopt.bits.rxtclass) {
|
2014-01-15 17:03:30 +08:00
|
|
|
int tclass = (int)ip6_tclass(np->rcv_flowinfo);
|
|
|
|
|
2012-02-09 17:35:49 +08:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
|
|
|
|
}
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
if (np->rxopt.bits.rxoinfo) {
|
2023-12-08 18:12:43 +08:00
|
|
|
int mcast_oif = READ_ONCE(np->mcast_oif);
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
struct in6_pktinfo src_info;
|
2023-12-08 18:12:43 +08:00
|
|
|
|
|
|
|
src_info.ipi6_ifindex = mcast_oif ? :
|
2008-12-16 18:07:45 +08:00
|
|
|
np->sticky_pktinfo.ipi6_ifindex;
|
2023-12-08 18:12:43 +08:00
|
|
|
src_info.ipi6_addr = mcast_oif ? sk->sk_v6_daddr :
|
|
|
|
np->sticky_pktinfo.ipi6_addr;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
|
|
|
|
}
|
|
|
|
if (np->rxopt.bits.rxohlim) {
|
2023-09-13 00:02:01 +08:00
|
|
|
int hlim = READ_ONCE(np->mcast_hops);
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);
|
|
|
|
}
|
2013-12-08 22:46:57 +08:00
|
|
|
if (np->rxopt.bits.rxflow) {
|
2013-12-13 00:07:58 +08:00
|
|
|
__be32 flowinfo = np->rcv_flowinfo;
|
|
|
|
|
2013-12-08 22:46:57 +08:00
|
|
|
put_cmsg(&msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
len -= msg.msg_controllen;
|
2022-09-02 08:28:53 +08:00
|
|
|
return copy_to_sockptr(optlen, &len, sizeof(int));
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
case IPV6_MTU:
|
|
|
|
{
|
|
|
|
struct dst_entry *dst;
|
2010-04-09 07:03:29 +08:00
|
|
|
|
2007-02-09 22:24:49 +08:00
|
|
|
val = 0;
|
2010-04-09 07:03:29 +08:00
|
|
|
rcu_read_lock();
|
|
|
|
dst = __sk_dst_get(sk);
|
|
|
|
if (dst)
|
2005-04-17 06:20:36 +08:00
|
|
|
val = dst_mtu(dst);
|
2010-04-09 07:03:29 +08:00
|
|
|
rcu_read_unlock();
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!val)
|
|
|
|
return -ENOTCONN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_V6ONLY:
|
2014-06-27 23:36:16 +08:00
|
|
|
val = sk->sk_ipv6only;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_RECVPKTINFO:
|
2005-04-17 06:20:36 +08:00
|
|
|
val = np->rxopt.bits.rxinfo;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292PKTINFO:
|
|
|
|
val = np->rxopt.bits.rxoinfo;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVHOPLIMIT:
|
2005-04-17 06:20:36 +08:00
|
|
|
val = np->rxopt.bits.rxhlim;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292HOPLIMIT:
|
|
|
|
val = np->rxopt.bits.rxohlim;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVRTHDR:
|
2005-04-17 06:20:36 +08:00
|
|
|
val = np->rxopt.bits.srcrt;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292RTHDR:
|
|
|
|
val = np->rxopt.bits.osrcrt;
|
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case IPV6_HOPOPTS:
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_RTHDRDSTOPTS:
|
|
|
|
case IPV6_RTHDR:
|
|
|
|
case IPV6_DSTOPTS:
|
|
|
|
{
|
2015-11-30 11:37:57 +08:00
|
|
|
struct ipv6_txoptions *opt;
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
|
2022-09-02 08:28:59 +08:00
|
|
|
sockopt_lock_sock(sk);
|
2016-04-05 23:10:15 +08:00
|
|
|
opt = rcu_dereference_protected(np->opt,
|
|
|
|
lockdep_sock_is_held(sk));
|
2015-11-30 11:37:57 +08:00
|
|
|
len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);
|
2022-09-02 08:28:59 +08:00
|
|
|
sockopt_release_sock(sk);
|
2008-05-28 16:23:47 +08:00
|
|
|
/* check if ipv6_getsockopt_sticky() returns err code */
|
|
|
|
if (len < 0)
|
|
|
|
return len;
|
2022-09-02 08:28:53 +08:00
|
|
|
return copy_to_sockptr(optlen, &len, sizeof(int));
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case IPV6_RECVHOPOPTS:
|
2005-04-17 06:20:36 +08:00
|
|
|
val = np->rxopt.bits.hopopts;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292HOPOPTS:
|
|
|
|
val = np->rxopt.bits.ohopopts;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVDSTOPTS:
|
2005-04-17 06:20:36 +08:00
|
|
|
val = np->rxopt.bits.dstopts;
|
|
|
|
break;
|
|
|
|
|
[IPV6]: Support several new sockopt / ancillary data in Advanced API (RFC3542).
Support several new socket options / ancillary data:
IPV6_RECVPKTINFO, IPV6_PKTINFO,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS,
IPV6_RECVDSTOPTS, IPV6_DSTOPTS, IPV6_RTHDRDSTOPTS,
IPV6_RECVRTHDR, IPV6_RTHDR,
IPV6_RECVHOPOPTS, IPV6_HOPOPTS
Old semantics are preserved as IPV6_2292xxxx so that
we can maintain backward compatibility.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
2005-09-08 08:59:17 +08:00
|
|
|
case IPV6_2292DSTOPTS:
|
|
|
|
val = np->rxopt.bits.odstopts;
|
|
|
|
break;
|
|
|
|
|
2005-09-08 09:19:03 +08:00
|
|
|
case IPV6_TCLASS:
|
|
|
|
val = np->tclass;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVTCLASS:
|
|
|
|
val = np->rxopt.bits.rxtclass;
|
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case IPV6_FLOWINFO:
|
|
|
|
val = np->rxopt.bits.rxflow;
|
|
|
|
break;
|
|
|
|
|
2010-04-23 19:26:07 +08:00
|
|
|
case IPV6_RECVPATHMTU:
|
|
|
|
val = np->rxopt.bits.rxpmtu;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_PATHMTU:
|
|
|
|
{
|
|
|
|
struct dst_entry *dst;
|
|
|
|
struct ip6_mtuinfo mtuinfo;
|
|
|
|
|
|
|
|
if (len < sizeof(mtuinfo))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
len = sizeof(mtuinfo);
|
|
|
|
memset(&mtuinfo, 0, sizeof(mtuinfo));
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
dst = __sk_dst_get(sk);
|
|
|
|
if (dst)
|
|
|
|
mtuinfo.ip6m_mtu = dst_mtu(dst);
|
|
|
|
rcu_read_unlock();
|
|
|
|
if (!mtuinfo.ip6m_mtu)
|
|
|
|
return -ENOTCONN;
|
|
|
|
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_to_sockptr(optlen, &len, sizeof(int)))
|
2010-04-23 19:26:07 +08:00
|
|
|
return -EFAULT;
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_to_sockptr(optval, &mtuinfo, len))
|
2010-04-23 19:26:07 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-21 22:08:28 +08:00
|
|
|
case IPV6_TRANSPARENT:
|
2023-08-16 16:15:41 +08:00
|
|
|
val = inet_test_bit(TRANSPARENT, sk);
|
2010-10-21 22:08:28 +08:00
|
|
|
break;
|
|
|
|
|
net-ipv6: add support for sockopt(SOL_IPV6, IPV6_FREEBIND)
So far we've been relying on sockopt(SOL_IP, IP_FREEBIND) being usable
even on IPv6 sockets.
However, it turns out it is perfectly reasonable to want to set freebind
on an AF_INET6 SOCK_RAW socket - but there is no way to set any SOL_IP
socket option on such a socket (they're all blindly errored out).
One use case for this is to allow spoofing src ip on a raw socket
via sendmsg cmsg.
Tested:
built, and booted
# python
>>> import socket
>>> SOL_IP = socket.SOL_IP
>>> SOL_IPV6 = socket.IPPROTO_IPV6
>>> IP_FREEBIND = 15
>>> IPV6_FREEBIND = 78
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
0
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
0
>>> s.setsockopt(SOL_IPV6, IPV6_FREEBIND, 1)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
1
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
1
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-27 12:32:42 +08:00
|
|
|
case IPV6_FREEBIND:
|
2023-08-16 16:15:37 +08:00
|
|
|
val = inet_test_bit(FREEBIND, sk);
|
net-ipv6: add support for sockopt(SOL_IPV6, IPV6_FREEBIND)
So far we've been relying on sockopt(SOL_IP, IP_FREEBIND) being usable
even on IPv6 sockets.
However, it turns out it is perfectly reasonable to want to set freebind
on an AF_INET6 SOCK_RAW socket - but there is no way to set any SOL_IP
socket option on such a socket (they're all blindly errored out).
One use case for this is to allow spoofing src ip on a raw socket
via sendmsg cmsg.
Tested:
built, and booted
# python
>>> import socket
>>> SOL_IP = socket.SOL_IP
>>> SOL_IPV6 = socket.IPPROTO_IPV6
>>> IP_FREEBIND = 15
>>> IPV6_FREEBIND = 78
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, 0)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
0
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
0
>>> s.setsockopt(SOL_IPV6, IPV6_FREEBIND, 1)
>>> s.getsockopt(SOL_IP, IP_FREEBIND)
1
>>> s.getsockopt(SOL_IPV6, IPV6_FREEBIND)
1
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-27 12:32:42 +08:00
|
|
|
break;
|
|
|
|
|
2010-10-21 22:08:28 +08:00
|
|
|
case IPV6_RECVORIGDSTADDR:
|
|
|
|
val = np->rxopt.bits.rxorigdstaddr;
|
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case IPV6_UNICAST_HOPS:
|
|
|
|
case IPV6_MULTICAST_HOPS:
|
2006-12-13 09:09:49 +08:00
|
|
|
{
|
|
|
|
struct dst_entry *dst;
|
|
|
|
|
|
|
|
if (optname == IPV6_UNICAST_HOPS)
|
2023-09-13 00:01:59 +08:00
|
|
|
val = READ_ONCE(np->hop_limit);
|
2006-12-13 09:09:49 +08:00
|
|
|
else
|
2023-09-13 00:02:01 +08:00
|
|
|
val = READ_ONCE(np->mcast_hops);
|
2006-12-13 09:09:49 +08:00
|
|
|
|
2010-04-09 07:03:29 +08:00
|
|
|
if (val < 0) {
|
|
|
|
rcu_read_lock();
|
|
|
|
dst = __sk_dst_get(sk);
|
|
|
|
if (dst)
|
2008-03-10 18:00:30 +08:00
|
|
|
val = ip6_dst_hoplimit(dst);
|
2010-04-09 07:03:29 +08:00
|
|
|
rcu_read_unlock();
|
2006-12-13 09:09:49 +08:00
|
|
|
}
|
2010-04-09 07:03:29 +08:00
|
|
|
|
2006-12-13 09:09:49 +08:00
|
|
|
if (val < 0)
|
2024-02-28 21:54:29 +08:00
|
|
|
val = READ_ONCE(sock_net(sk)->ipv6.devconf_all->hop_limit);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
2006-12-13 09:09:49 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
case IPV6_MULTICAST_LOOP:
|
2023-09-13 00:02:00 +08:00
|
|
|
val = inet6_test_bit(MC6_LOOP, sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_MULTICAST_IF:
|
2023-12-08 18:12:43 +08:00
|
|
|
val = READ_ONCE(np->mcast_oif);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2018-09-10 16:27:15 +08:00
|
|
|
case IPV6_MULTICAST_ALL:
|
2023-09-13 00:02:05 +08:00
|
|
|
val = inet6_test_bit(MC6_ALL, sk);
|
2018-09-10 16:27:15 +08:00
|
|
|
break;
|
|
|
|
|
2012-02-08 17:11:08 +08:00
|
|
|
case IPV6_UNICAST_IF:
|
2023-12-08 18:12:44 +08:00
|
|
|
val = (__force int)htonl((__u32) READ_ONCE(np->ucast_oif));
|
2012-02-08 17:11:08 +08:00
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case IPV6_MTU_DISCOVER:
|
2023-09-13 00:02:11 +08:00
|
|
|
val = READ_ONCE(np->pmtudisc);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_RECVERR:
|
2023-09-13 00:02:08 +08:00
|
|
|
val = inet6_test_bit(RECVERR6, sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IPV6_FLOWINFO_SEND:
|
2023-09-13 00:02:12 +08:00
|
|
|
val = inet6_test_bit(SNDFLOW, sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
2013-11-08 00:53:12 +08:00
|
|
|
case IPV6_FLOWLABEL_MGR:
|
|
|
|
{
|
|
|
|
struct in6_flowlabel_req freq;
|
2014-01-18 00:15:04 +08:00
|
|
|
int flags;
|
2013-11-08 00:53:12 +08:00
|
|
|
|
|
|
|
if (len < sizeof(freq))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_from_sockptr(&freq, optval, sizeof(freq)))
|
2013-11-08 00:53:12 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (freq.flr_action != IPV6_FL_A_GET)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
len = sizeof(freq);
|
2014-01-18 00:15:04 +08:00
|
|
|
flags = freq.flr_flags;
|
|
|
|
|
2013-11-08 00:53:12 +08:00
|
|
|
memset(&freq, 0, sizeof(freq));
|
|
|
|
|
2014-01-18 00:15:04 +08:00
|
|
|
val = ipv6_flowlabel_opt_get(sk, &freq, flags);
|
2013-11-08 00:53:12 +08:00
|
|
|
if (val < 0)
|
|
|
|
return val;
|
|
|
|
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_to_sockptr(optlen, &len, sizeof(int)))
|
2013-11-08 00:53:12 +08:00
|
|
|
return -EFAULT;
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_to_sockptr(optval, &freq, len))
|
2013-11-08 00:53:12 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-03-25 08:37:42 +08:00
|
|
|
case IPV6_ADDR_PREFERENCES:
|
2023-09-18 22:23:21 +08:00
|
|
|
{
|
|
|
|
u8 srcprefs = READ_ONCE(np->srcprefs);
|
2008-03-25 08:37:42 +08:00
|
|
|
val = 0;
|
|
|
|
|
2023-09-18 22:23:21 +08:00
|
|
|
if (srcprefs & IPV6_PREFER_SRC_TMP)
|
2008-03-25 08:37:42 +08:00
|
|
|
val |= IPV6_PREFER_SRC_TMP;
|
2023-09-18 22:23:21 +08:00
|
|
|
else if (srcprefs & IPV6_PREFER_SRC_PUBLIC)
|
2008-03-25 08:37:42 +08:00
|
|
|
val |= IPV6_PREFER_SRC_PUBLIC;
|
|
|
|
else {
|
|
|
|
/* XXX: should we return system default? */
|
|
|
|
val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT;
|
|
|
|
}
|
|
|
|
|
2023-09-18 22:23:21 +08:00
|
|
|
if (srcprefs & IPV6_PREFER_SRC_COA)
|
2008-03-25 08:37:42 +08:00
|
|
|
val |= IPV6_PREFER_SRC_COA;
|
|
|
|
else
|
|
|
|
val |= IPV6_PREFER_SRC_HOME;
|
|
|
|
break;
|
2023-09-18 22:23:21 +08:00
|
|
|
}
|
IPv6: Generic TTL Security Mechanism (final version)
This patch adds IPv6 support for RFC5082 Generalized TTL Security Mechanism.
Not to users of mapped address; the IPV6 and IPV4 socket options are seperate.
The server does have to deal with both IPv4 and IPv6 socket options
and the client has to handle the different for each family.
On client:
int ttl = 255;
getaddrinfo(argv[1], argv[2], &hint, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET) {
setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
} else if (rp->ai_family == AF_INET6) {
setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
&ttl, sizeof(ttl)))
}
if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) {
...
On server:
int minttl = 255 - maxhops;
getaddrinfo(NULL, port, &hints, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET6)
setsockopt(s, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
&minttl, sizeof(minttl));
setsockopt(s, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
if (bind(s, rp->ai_addr, rp->ai_addrlen) == 0)
break
...
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2010-04-23 06:24:53 +08:00
|
|
|
case IPV6_MINHOPCOUNT:
|
2023-09-13 00:02:03 +08:00
|
|
|
val = READ_ONCE(np->min_hopcount);
|
IPv6: Generic TTL Security Mechanism (final version)
This patch adds IPv6 support for RFC5082 Generalized TTL Security Mechanism.
Not to users of mapped address; the IPV6 and IPV4 socket options are seperate.
The server does have to deal with both IPv4 and IPv6 socket options
and the client has to handle the different for each family.
On client:
int ttl = 255;
getaddrinfo(argv[1], argv[2], &hint, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET) {
setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
} else if (rp->ai_family == AF_INET6) {
setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
&ttl, sizeof(ttl)))
}
if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) {
...
On server:
int minttl = 255 - maxhops;
getaddrinfo(NULL, port, &hints, &result);
for (rp = result; rp != NULL; rp = rp->ai_next) {
s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (s < 0) continue;
if (rp->ai_family == AF_INET6)
setsockopt(s, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
&minttl, sizeof(minttl));
setsockopt(s, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
if (bind(s, rp->ai_addr, rp->ai_addrlen) == 0)
break
...
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2010-04-23 06:24:53 +08:00
|
|
|
break;
|
2010-04-23 19:26:07 +08:00
|
|
|
|
|
|
|
case IPV6_DONTFRAG:
|
2023-09-13 00:02:07 +08:00
|
|
|
val = inet6_test_bit(DONTFRAG, sk);
|
2010-04-23 19:26:07 +08:00
|
|
|
break;
|
2008-03-25 08:37:42 +08:00
|
|
|
|
2014-07-02 12:33:10 +08:00
|
|
|
case IPV6_AUTOFLOWLABEL:
|
2023-09-13 00:02:06 +08:00
|
|
|
val = ip6_autoflowlabel(sock_net(sk), sk);
|
2014-07-02 12:33:10 +08:00
|
|
|
break;
|
|
|
|
|
2016-11-02 23:02:17 +08:00
|
|
|
case IPV6_RECVFRAGSIZE:
|
|
|
|
val = np->rxopt.bits.recvfragsize;
|
|
|
|
break;
|
|
|
|
|
2024-03-04 19:32:08 +08:00
|
|
|
case IPV6_ROUTER_ALERT:
|
|
|
|
val = inet6_test_bit(RTALERT, sk);
|
|
|
|
break;
|
|
|
|
|
2019-03-02 07:31:03 +08:00
|
|
|
case IPV6_ROUTER_ALERT_ISOLATE:
|
2023-09-13 00:02:10 +08:00
|
|
|
val = inet6_test_bit(RTALERT_ISOLATE, sk);
|
2019-03-02 07:31:03 +08:00
|
|
|
break;
|
|
|
|
|
2020-07-24 21:03:10 +08:00
|
|
|
case IPV6_RECVERR_RFC4884:
|
2023-09-13 00:02:04 +08:00
|
|
|
val = inet6_test_bit(RECVERR6_RFC4884, sk);
|
2020-07-24 21:03:10 +08:00
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
default:
|
2007-12-17 05:39:57 +08:00
|
|
|
return -ENOPROTOOPT;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
len = min_t(unsigned int, sizeof(int), len);
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_to_sockptr(optlen, &len, sizeof(int)))
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EFAULT;
|
2022-09-02 08:28:53 +08:00
|
|
|
if (copy_to_sockptr(optval, &val, len))
|
2005-04-17 06:20:36 +08:00
|
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-21 14:45:21 +08:00
|
|
|
int ipv6_getsockopt(struct sock *sk, int level, int optname,
|
|
|
|
char __user *optval, int __user *optlen)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (level == SOL_IP && sk->sk_type != SOCK_RAW)
|
|
|
|
return udp_prot.getsockopt(sk, level, optname, optval, optlen);
|
|
|
|
|
2014-08-25 04:53:10 +08:00
|
|
|
if (level != SOL_IPV6)
|
2006-03-21 14:45:21 +08:00
|
|
|
return -ENOPROTOOPT;
|
|
|
|
|
2022-09-02 08:28:53 +08:00
|
|
|
err = do_ipv6_getsockopt(sk, level, optname,
|
|
|
|
USER_SOCKPTR(optval), USER_SOCKPTR(optlen));
|
2006-03-21 14:45:21 +08:00
|
|
|
#ifdef CONFIG_NETFILTER
|
2007-12-17 05:39:57 +08:00
|
|
|
/* we need to exclude all possible ENOPROTOOPTs except default case */
|
|
|
|
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
|
2006-03-21 14:45:21 +08:00
|
|
|
int len;
|
|
|
|
|
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2018-02-08 19:19:00 +08:00
|
|
|
err = nf_getsockopt(sk, PF_INET6, optname, optval, &len);
|
2006-03-21 14:45:21 +08:00
|
|
|
if (err >= 0)
|
|
|
|
err = put_user(len, optlen);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return err;
|
|
|
|
}
|
2007-02-22 21:05:40 +08:00
|
|
|
EXPORT_SYMBOL(ipv6_getsockopt);
|