diff options
author | Martin KaFai Lau <martin.lau@kernel.org> | 2022-09-02 03:29:31 +0300 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2022-09-03 06:34:32 +0300 |
commit | 38566ec06f52250c4abaa7447aae676e0b881c46 (patch) | |
tree | 766449461e33aa6e1eb0dff0aa206e22b318a3e4 /net/core | |
parent | fd969f25fe24be515278d28cbf86dde39be8a495 (diff) | |
download | linux-38566ec06f52250c4abaa7447aae676e0b881c46.tar.xz |
bpf: Change bpf_getsockopt(SOL_IPV6) to reuse do_ipv6_getsockopt()
This patch changes bpf_getsockopt(SOL_IPV6) to reuse
do_ipv6_getsockopt(). It removes the duplicated code from
bpf_getsockopt(SOL_IPV6).
This also makes bpf_getsockopt(SOL_IPV6) supporting the same
set of optnames as in bpf_setsockopt(SOL_IPV6). In particular,
this adds IPV6_AUTOFLOWLABEL support to bpf_getsockopt(SOL_IPV6).
ipv6 could be compiled as a module. Like how other code solved it
with stubs in ipv6_stubs.h, this patch adds the do_ipv6_getsockopt
to the ipv6_bpf_stub.
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/r/20220902002931.2896218-1-kafai@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/filter.c | 55 |
1 files changed, 24 insertions, 31 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index 33275460fe66..ee768bb5b5ab 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -5191,8 +5191,9 @@ static int sol_ip_sockopt(struct sock *sk, int optname, KERNEL_SOCKPTR(optval), *optlen); } -static int sol_ipv6_setsockopt(struct sock *sk, int optname, - char *optval, int optlen) +static int sol_ipv6_sockopt(struct sock *sk, int optname, + char *optval, int *optlen, + bool getopt) { if (sk->sk_family != AF_INET6) return -EINVAL; @@ -5200,15 +5201,20 @@ static int sol_ipv6_setsockopt(struct sock *sk, int optname, switch (optname) { case IPV6_TCLASS: case IPV6_AUTOFLOWLABEL: - if (optlen != sizeof(int)) + if (*optlen != sizeof(int)) return -EINVAL; break; default: return -EINVAL; } + if (getopt) + return ipv6_bpf_stub->ipv6_getsockopt(sk, SOL_IPV6, optname, + KERNEL_SOCKPTR(optval), + KERNEL_SOCKPTR(optlen)); + return ipv6_bpf_stub->ipv6_setsockopt(sk, SOL_IPV6, optname, - KERNEL_SOCKPTR(optval), optlen); + KERNEL_SOCKPTR(optval), *optlen); } static int __bpf_setsockopt(struct sock *sk, int level, int optname, @@ -5222,7 +5228,7 @@ static int __bpf_setsockopt(struct sock *sk, int level, int optname, else if (IS_ENABLED(CONFIG_INET) && level == SOL_IP) return sol_ip_sockopt(sk, optname, optval, &optlen, false); else if (IS_ENABLED(CONFIG_IPV6) && level == SOL_IPV6) - return sol_ipv6_setsockopt(sk, optname, optval, optlen); + return sol_ipv6_sockopt(sk, optname, optval, &optlen, false); else if (IS_ENABLED(CONFIG_INET) && level == SOL_TCP) return sol_tcp_sockopt(sk, optname, optval, &optlen, false); @@ -5240,43 +5246,30 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname, static int __bpf_getsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { - int err = 0, saved_optlen = optlen; + int err, saved_optlen = optlen; - if (!sk_fullsock(sk)) - goto err_clear; + if (!sk_fullsock(sk)) { + err = -EINVAL; + goto done; + } - if (level == SOL_SOCKET) { + if (level == SOL_SOCKET) err = sol_socket_sockopt(sk, optname, optval, &optlen, true); - } else if (IS_ENABLED(CONFIG_INET) && level == SOL_TCP) { + else if (IS_ENABLED(CONFIG_INET) && level == SOL_TCP) err = sol_tcp_sockopt(sk, optname, optval, &optlen, true); - } else if (IS_ENABLED(CONFIG_INET) && level == SOL_IP) { + else if (IS_ENABLED(CONFIG_INET) && level == SOL_IP) err = sol_ip_sockopt(sk, optname, optval, &optlen, true); - } else if (IS_ENABLED(CONFIG_IPV6) && level == SOL_IPV6) { - struct ipv6_pinfo *np = inet6_sk(sk); - - if (optlen != sizeof(int) || sk->sk_family != AF_INET6) - goto err_clear; - - /* Only some options are supported */ - switch (optname) { - case IPV6_TCLASS: - *((int *)optval) = (int)np->tclass; - break; - default: - goto err_clear; - } - } else { - goto err_clear; - } + else if (IS_ENABLED(CONFIG_IPV6) && level == SOL_IPV6) + err = sol_ipv6_sockopt(sk, optname, optval, &optlen, true); + else + err = -EINVAL; +done: if (err) optlen = 0; if (optlen < saved_optlen) memset(optval + optlen, 0, saved_optlen - optlen); return err; -err_clear: - memset(optval, 0, optlen); - return -EINVAL; } static int _bpf_getsockopt(struct sock *sk, int level, int optname, |