Commit b975b83becfc0d17b490e64a40f5c9c3e69f574f
Committed by
Riku Voipio
1 parent
6f932f91
linux-user: Added IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP flags to setsockopt
linux-user: Added IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP flags to setsockopt Signed-off-by: Lionel Landwerlin <lionel.landwerlin@openwide.fr> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
Showing
2 changed files
with
45 additions
and
0 deletions
linux-user/syscall.c
| ... | ... | @@ -943,6 +943,24 @@ static abi_long do_select(int n, |
| 943 | 943 | return ret; |
| 944 | 944 | } |
| 945 | 945 | |
| 946 | +static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn, | |
| 947 | + abi_ulong target_addr, | |
| 948 | + socklen_t len) | |
| 949 | +{ | |
| 950 | + struct target_ip_mreqn *target_smreqn; | |
| 951 | + | |
| 952 | + target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1); | |
| 953 | + if (!target_smreqn) | |
| 954 | + return -TARGET_EFAULT; | |
| 955 | + mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr; | |
| 956 | + mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr; | |
| 957 | + if (len == sizeof(struct target_ip_mreqn)) | |
| 958 | + mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex); | |
| 959 | + unlock_user(target_smreqn, target_addr, 0); | |
| 960 | + | |
| 961 | + return 0; | |
| 962 | +} | |
| 963 | + | |
| 946 | 964 | static inline abi_long target_to_host_sockaddr(struct sockaddr *addr, |
| 947 | 965 | abi_ulong target_addr, |
| 948 | 966 | socklen_t len) |
| ... | ... | @@ -1118,6 +1136,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, |
| 1118 | 1136 | { |
| 1119 | 1137 | abi_long ret; |
| 1120 | 1138 | int val; |
| 1139 | + struct ip_mreqn *ip_mreq; | |
| 1121 | 1140 | |
| 1122 | 1141 | switch(level) { |
| 1123 | 1142 | case SOL_TCP: |
| ... | ... | @@ -1156,6 +1175,17 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, |
| 1156 | 1175 | } |
| 1157 | 1176 | ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); |
| 1158 | 1177 | break; |
| 1178 | + case IP_ADD_MEMBERSHIP: | |
| 1179 | + case IP_DROP_MEMBERSHIP: | |
| 1180 | + if (optlen < sizeof (struct target_ip_mreq) || | |
| 1181 | + optlen > sizeof (struct target_ip_mreqn)) | |
| 1182 | + return -TARGET_EINVAL; | |
| 1183 | + | |
| 1184 | + ip_mreq = (struct ip_mreqn *) alloca(optlen); | |
| 1185 | + target_to_host_ip_mreq(ip_mreq, optval_addr, optlen); | |
| 1186 | + ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen)); | |
| 1187 | + break; | |
| 1188 | + | |
| 1159 | 1189 | default: |
| 1160 | 1190 | goto unimplemented; |
| 1161 | 1191 | } | ... | ... |
linux-user/syscall_defs.h
| ... | ... | @@ -111,6 +111,21 @@ struct target_sockaddr { |
| 111 | 111 | uint8_t sa_data[14]; |
| 112 | 112 | }; |
| 113 | 113 | |
| 114 | +struct target_in_addr { | |
| 115 | + uint32_t s_addr; /* big endian */ | |
| 116 | +}; | |
| 117 | + | |
| 118 | +struct target_ip_mreq { | |
| 119 | + struct target_in_addr imr_multiaddr; | |
| 120 | + struct target_in_addr imr_address; | |
| 121 | +}; | |
| 122 | + | |
| 123 | +struct target_ip_mreqn { | |
| 124 | + struct target_in_addr imr_multiaddr; | |
| 125 | + struct target_in_addr imr_address; | |
| 126 | + abi_long imr_ifindex; | |
| 127 | +}; | |
| 128 | + | |
| 114 | 129 | struct target_timeval { |
| 115 | 130 | abi_long tv_sec; |
| 116 | 131 | abi_long tv_usec; | ... | ... |