Commit b975b83becfc0d17b490e64a40f5c9c3e69f574f

Authored by Lionel Landwerlin
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>
linux-user/syscall.c
@@ -943,6 +943,24 @@ static abi_long do_select(int n, @@ -943,6 +943,24 @@ static abi_long do_select(int n,
943 return ret; 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 static inline abi_long target_to_host_sockaddr(struct sockaddr *addr, 964 static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
947 abi_ulong target_addr, 965 abi_ulong target_addr,
948 socklen_t len) 966 socklen_t len)
@@ -1118,6 +1136,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, @@ -1118,6 +1136,7 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
1118 { 1136 {
1119 abi_long ret; 1137 abi_long ret;
1120 int val; 1138 int val;
  1139 + struct ip_mreqn *ip_mreq;
1121 1140
1122 switch(level) { 1141 switch(level) {
1123 case SOL_TCP: 1142 case SOL_TCP:
@@ -1156,6 +1175,17 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, @@ -1156,6 +1175,17 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
1156 } 1175 }
1157 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val))); 1176 ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
1158 break; 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 default: 1189 default:
1160 goto unimplemented; 1190 goto unimplemented;
1161 } 1191 }
linux-user/syscall_defs.h
@@ -111,6 +111,21 @@ struct target_sockaddr { @@ -111,6 +111,21 @@ struct target_sockaddr {
111 uint8_t sa_data[14]; 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 struct target_timeval { 129 struct target_timeval {
115 abi_long tv_sec; 130 abi_long tv_sec;
116 abi_long tv_usec; 131 abi_long tv_usec;