@@ -138,5 +138,263 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
return ret;
}
+/* setsockopt(2) */
+static inline abi_long do_bsd_setsockopt(int sockfd, int level, int optname,
+ abi_ulong optval_addr, socklen_t optlen)
+{
+ abi_long ret;
+ int val;
+ struct ip_mreqn *ip_mreq;
+ void *p;
+
+ switch (level) {
+ case IPPROTO_TCP:
+ /* TCP options all take an 'int' value. */
+ if (optlen < sizeof(uint32_t)) {
+ return -TARGET_EINVAL;
+ }
+ if (get_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
+ break;
+
+ case IPPROTO_IP:
+ switch (optname) {
+ case IP_OPTIONS:
+ p = lock_user(VERIFY_READ, optval_addr, optlen, 0);
+ if (p == NULL) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(setsockopt(sockfd, level, optname, p, optlen));
+ unlock_user(p, optval_addr, 0);
+ break;
+ case IP_HDRINCL:/* int; header is included with data */
+ case IP_TOS: /* int; IP type of service and preced. */
+ case IP_TTL: /* int; IP time to live */
+ case IP_RECVOPTS: /* bool; receive all IP opts w/dgram */
+ case IP_RECVRETOPTS: /* bool; receive IP opts for response */
+ case IP_RECVDSTADDR: /* bool; receive IP dst addr w/dgram */
+ case IP_MULTICAST_IF:/* u_char; set/get IP multicast i/f */
+ case IP_MULTICAST_TTL:/* u_char; set/get IP multicast ttl */
+ case IP_MULTICAST_LOOP:/*u_char;set/get IP multicast loopback */
+ case IP_PORTRANGE: /* int; range to choose for unspec port */
+ case IP_RECVIF: /* bool; receive reception if w/dgram */
+ case IP_IPSEC_POLICY: /* int; set/get security policy */
+ case IP_RECVTTL: /* bool; receive reception TTL w/dgram */
+ val = 0;
+ if (optlen >= sizeof(uint32_t)) {
+ if (get_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ } else if (optlen >= 1) {
+ if (get_user_u8(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ }
+ ret = get_errno(setsockopt(sockfd, level, optname, &val,
+ sizeof(val)));
+ break;
+
+ case IP_ADD_MEMBERSHIP: /*ip_mreq; add an IP group membership */
+ case IP_DROP_MEMBERSHIP:/*ip_mreq; drop an IP group membership*/
+ if (optlen < sizeof(struct target_ip_mreq) ||
+ optlen > sizeof(struct target_ip_mreqn)) {
+ return -TARGET_EINVAL;
+ }
+ ip_mreq = (struct ip_mreqn *) alloca(optlen);
+ target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
+ ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq,
+ optlen));
+ break;
+
+ default:
+ goto unimplemented;
+ }
+ break;
+
+ case IPPROTO_IPV6:
+ switch (optname) {
+ case IPV6_UNICAST_HOPS: /* int; IP6 hops */
+ case IPV6_MULTICAST_IF: /* u_int; set/get IP6 multicast i/f */
+ case IPV6_MULTICAST_HOPS: /* int; set/get IP6 multicast hops */
+ case IPV6_MULTICAST_LOOP: /* u_int; set/get IP6 multicast loopback */
+ case IPV6_PORTRANGE: /* int; range to choose for unspec port */
+ case IPV6_CHECKSUM: /* int; checksum offset for raw socket */
+ case IPV6_V6ONLY: /* bool; make AF_INET6 sockets v6 only */
+ case IPV6_RECVPKTINFO: /* bool; recv if, dst addr */
+ case IPV6_RECVHOPLIMIT: /* bool; recv hop limit */
+ case IPV6_RECVRTHDR: /* bool; recv routing header */
+ case IPV6_RECVHOPOPTS: /* bool; recv hop-by-hop option */
+ case IPV6_RECVDSTOPTS: /* bool; recv dst option after rthdr */
+ case IPV6_USE_MIN_MTU: /* bool; send packets at the minimum MTU */
+ case IPV6_RECVPATHMTU: /* bool; notify an according MTU */
+ case IPV6_HOPLIMIT: /* int; send hop limit */
+ case IPV6_RECVTCLASS: /* bool; recv traffic class values */
+ case IPV6_AUTOFLOWLABEL: /* bool; attach flowlabel automagically */
+ case IPV6_TCLASS: /* int; send traffic class value */
+ case IPV6_DONTFRAG: /* bool; disable IPv6 fragmentation */
+ case IPV6_PREFER_TEMPADDR: /* int; prefer temporary addresses */
+ case IPV6_BINDANY: /* bool: allow bind to any address */
+#ifdef IPV6_BINDMULTI
+ case IPV6_BINDMULTI: /* bool; allow multibind to same addr/port*/
+#endif /* IPV6_BINDMULTI */
+#ifdef IPV6_RSS_LISTEN_BUCKET
+ case IPV6_RSS_LISTEN_BUCKET: /* int; set RSS listen bucket */
+#endif /* IPV6_RSS_LISTEN_BUCKET */
+#ifdef IPV6_FLOWID
+ case IPV6_FLOWID: /* int; flowid of given socket */
+#endif /* IPV6_FLOWID */
+#ifdef IPV6_FLOWTYPE
+ case IPV6_FLOWTYPE: /* int; flowtype of given socket */
+#endif /* IPV6_FLOWTYPE */
+#ifdef IPV6_RSSBUCKETID
+ case IPV6_RSSBUCKETID: /* int; RSS bucket ID of given socket */
+#endif /* IPV6_RSSBUCKETID */
+ val = 0;
+ if (optlen >= sizeof(uint32_t)) {
+ if (get_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ } else if (optlen >= 1) {
+ if (get_user_u8(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ }
+ ret = get_errno(setsockopt(sockfd, level, optname, &val,
+ sizeof(val)));
+ break;
+
+ case IPV6_JOIN_GROUP: /* ipv6_mreq; join a group membership */
+ case IPV6_LEAVE_GROUP: /* ipv6_mreq; leave a group membership */
+ case ICMP6_FILTER: /* icmp6_filter; icmp6 filter */
+ case IPV6_IPSEC_POLICY: /* struct; get/set security policy */
+ case IPV6_FW_ADD: /* add a firewall rule to chain */
+ case IPV6_FW_DEL: /* delete a firewall rule from chain */
+ case IPV6_FW_FLUSH: /* flush firewall rule chain */
+ case IPV6_FW_ZERO: /* clear single/all firewall counter(s) */
+ case IPV6_FW_GET: /* get entire firewall rule chain */
+ case IPV6_RTHDRDSTOPTS: /* ip6_dest; send dst option before rthdr */
+ case IPV6_PATHMTU: /* mtuinfo; get the current path MTU */
+ case IPV6_PKTINFO: /* in6_pktinfo; send if, src addr */
+ case IPV6_NEXTHOP: /* sockaddr; next hop addr */
+ case IPV6_HOPOPTS: /* ip6_hbh; send hop-by-hop option */
+ case IPV6_DSTOPTS: /* ip6_dest; send dst option befor rthdr */
+ case IPV6_RTHDR: /* ip6_rthdr; send routing header */
+ case IPV6_MSFILTER: /* struct __msfilterreq; */
+ default:
+ goto unimplemented;
+ }
+ break;
+
+ case TARGET_SOL_SOCKET:
+ switch (optname) {
+ /* Options with 'int' argument. */
+ case TARGET_SO_DEBUG:
+ optname = SO_DEBUG;
+ break;
+
+ case TARGET_SO_REUSEADDR:
+ optname = SO_REUSEADDR;
+ break;
+
+ case TARGET_SO_REUSEPORT:
+ optname = SO_REUSEPORT;
+ break;
+
+ case TARGET_SO_KEEPALIVE:
+ optname = SO_KEEPALIVE;
+ break;
+
+ case TARGET_SO_DONTROUTE:
+ optname = SO_DONTROUTE;
+ break;
+
+ case TARGET_SO_LINGER:
+ optname = SO_LINGER;
+ break;
+
+ case TARGET_SO_BROADCAST:
+ optname = SO_BROADCAST;
+ break;
+
+ case TARGET_SO_OOBINLINE:
+ optname = SO_OOBINLINE;
+ break;
+
+ case TARGET_SO_SNDBUF:
+ optname = SO_SNDBUF;
+ break;
+
+ case TARGET_SO_RCVBUF:
+ optname = SO_RCVBUF;
+ break;
+
+ case TARGET_SO_SNDLOWAT:
+ optname = SO_RCVLOWAT;
+ break;
+
+ case TARGET_SO_RCVLOWAT:
+ optname = SO_RCVLOWAT;
+ break;
+
+ case TARGET_SO_SNDTIMEO:
+ optname = SO_SNDTIMEO;
+ break;
+
+ case TARGET_SO_RCVTIMEO:
+ optname = SO_RCVTIMEO;
+ break;
+
+ case TARGET_SO_ACCEPTFILTER:
+ goto unimplemented;
+
+ case TARGET_SO_NOSIGPIPE:
+ optname = SO_NOSIGPIPE;
+ break;
+
+ case TARGET_SO_TIMESTAMP:
+ optname = SO_TIMESTAMP;
+ break;
+
+ case TARGET_SO_BINTIME:
+ optname = SO_BINTIME;
+ break;
+
+ case TARGET_SO_ERROR:
+ optname = SO_ERROR;
+ break;
+
+ case TARGET_SO_SETFIB:
+ optname = SO_SETFIB;
+ break;
+
+#ifdef SO_USER_COOKIE
+ case TARGET_SO_USER_COOKIE:
+ optname = SO_USER_COOKIE;
+ break;
+#endif
+ default:
+ goto unimplemented;
+ }
+ if (optlen < sizeof(uint32_t)) {
+ return -TARGET_EINVAL;
+ }
+ if (get_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val,
+ sizeof(val)));
+ break;
+ default:
+unimplemented:
+ gemu_log("Unsupported setsockopt level=%d optname=%d\n",
+ level, optname);
+ ret = -TARGET_ENOPROTOOPT;
+ }
+
+ return ret;
+}
+
#endif /* BSD_USER_FREEBSD_OS_SOCKET_H */