linux: Support ICMP6_FILTER socket option translation
Handle Linux IPPROTO_ICMPV6 socket options in the Linuxulator and map ICMP6_FILTER for both getsockopt(2) and setsockopt(2). Linux and FreeBSD use inverted bit semantics for struct icmp6_filter, so invert the filter contents before/after calling setsockopt/getsockopt. Signed-off-by: Ricardo Branco <rbranco@suse.de> PR: 294434 Reviewed by: pouria Pull-Request: https://github.com/freebsd/freebsd-src/pull/2138
This commit is contained in:
committed by
Pouria Mousavizadeh Tehrani
parent
3a54aa3b09
commit
64e2715f5d
@@ -52,6 +52,7 @@
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#ifdef INET6
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
@@ -622,6 +623,19 @@ bsd_to_linux_tcp_user_timeout(u_int bsd_timeout)
|
||||
return (bsd_timeout * 1000U);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
static int
|
||||
linux_to_bsd_icmp6_sockopt(int opt)
|
||||
{
|
||||
|
||||
switch (opt) {
|
||||
case LINUX_ICMP6_FILTER:
|
||||
return (ICMP6_FILTER);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
linux_to_bsd_msg_flags(int flags)
|
||||
{
|
||||
@@ -2175,6 +2189,29 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#ifdef INET6
|
||||
case IPPROTO_ICMPV6: {
|
||||
struct icmp6_filter f;
|
||||
int i;
|
||||
|
||||
name = linux_to_bsd_icmp6_sockopt(args->optname);
|
||||
if (name != ICMP6_FILTER)
|
||||
break;
|
||||
|
||||
if (args->optlen != sizeof(f))
|
||||
return (EINVAL);
|
||||
|
||||
error = copyin(PTRIN(args->optval), &f, sizeof(f));
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Linux uses opposite values for pass/block in ICMPv6 */
|
||||
for (i = 0; i < nitems(f.icmp6_filt); i++)
|
||||
f.icmp6_filt[i] = ~f.icmp6_filt[i];
|
||||
return (kern_setsockopt(td, args->s, IPPROTO_ICMPV6,
|
||||
ICMP6_FILTER, &f, UIO_SYSSPACE, sizeof(f)));
|
||||
}
|
||||
#endif
|
||||
case SOL_NETLINK:
|
||||
name = args->optname;
|
||||
break;
|
||||
@@ -2435,6 +2472,36 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#ifdef INET6
|
||||
case IPPROTO_ICMPV6: {
|
||||
struct icmp6_filter f;
|
||||
int i;
|
||||
|
||||
name = linux_to_bsd_icmp6_sockopt(args->optname);
|
||||
if (name != ICMP6_FILTER)
|
||||
break;
|
||||
|
||||
error = copyin(PTRIN(args->optlen), &len, sizeof(len));
|
||||
if (error)
|
||||
return (error);
|
||||
if (len != sizeof(f))
|
||||
return (EINVAL);
|
||||
|
||||
error = kern_getsockopt(td, args->s, IPPROTO_ICMPV6,
|
||||
ICMP6_FILTER, &f, UIO_SYSSPACE, &len);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Linux uses opposite values for pass/block in ICMPv6 */
|
||||
for (i = 0; i < nitems(f.icmp6_filt); i++)
|
||||
f.icmp6_filt[i] = ~f.icmp6_filt[i];
|
||||
error = copyout(&f, PTRIN(args->optval), len);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
return (copyout(&len, PTRIN(args->optlen), sizeof(socklen_t)));
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
name = -1;
|
||||
break;
|
||||
|
||||
@@ -324,6 +324,8 @@ int linux_accept(struct thread *td, struct linux_accept_args *args);
|
||||
#define LINUX_TCP_MD5SIG 14
|
||||
#define LINUX_TCP_USER_TIMEOUT 18
|
||||
|
||||
#define LINUX_ICMP6_FILTER 1
|
||||
|
||||
struct l_ifmap {
|
||||
l_ulong mem_start;
|
||||
l_ulong mem_end;
|
||||
|
||||
Reference in New Issue
Block a user