diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 76481261b1..674942cdf4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1137,6 +1137,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, abi_long ret; int val; struct ip_mreqn *ip_mreq; + struct ip_mreq_source *ip_mreq_source; switch(level) { case SOL_TCP: @@ -1186,6 +1187,18 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen)); break; + case IP_BLOCK_SOURCE: + case IP_UNBLOCK_SOURCE: + case IP_ADD_SOURCE_MEMBERSHIP: + case IP_DROP_SOURCE_MEMBERSHIP: + if (optlen != sizeof (struct target_ip_mreq_source)) + return -TARGET_EINVAL; + + ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1); + ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen)); + unlock_user (ip_mreq_source, optval_addr, 0); + break; + default: goto unimplemented; } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 6e68c91ca6..89b73b8ed1 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -126,6 +126,13 @@ struct target_ip_mreqn { abi_long imr_ifindex; }; +struct target_ip_mreq_source { + /* big endian */ + uint32_t imr_multiaddr; + uint32_t imr_interface; + uint32_t imr_sourceaddr; +}; + struct target_timeval { abi_long tv_sec; abi_long tv_usec;