diff mbox series

[v2,13/37] bsd-user: Add do_bsd_getsockopt

Message ID 20260518-misc-2026q2-v2-13-6c16fe448301@bsdimp.com
State New
Headers show
Series bsd-user: Upstream most of the remaining system calls | expand

Commit Message

Warner Losh May 18, 2026, 9:27 p.m. UTC
Add the getsockopt(2) implementation handling SOL_SOCKET, IPPROTO_TCP,
IPPROTO_IP, and IPPROTO_IPV6 levels with proper target-to-host option
name translation.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
Assisted-by: Claude Opus 4.6 (1M context)
---
 bsd-user/freebsd/os-socket.h | 284 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 284 insertions(+)

Comments

Pierrick Bouvier May 22, 2026, 11:28 p.m. UTC | #1
On 5/18/2026 2:27 PM, Warner Losh wrote:
> Add the getsockopt(2) implementation handling SOL_SOCKET, IPPROTO_TCP,
> IPPROTO_IP, and IPPROTO_IPV6 levels with proper target-to-host option
> name translation.
> 
> Signed-off-by: Stacey Son <sson@FreeBSD.org>
> Signed-off-by: Mikaël Urankar <mikael.urankar@gmail.com>
> Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
> Signed-off-by: Warner Losh <imp@bsdimp.com>
> Assisted-by: Claude Opus 4.6 (1M context)
> ---
>  bsd-user/freebsd/os-socket.h | 284 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 284 insertions(+)
> 
> diff --git a/bsd-user/freebsd/os-socket.h b/bsd-user/freebsd/os-socket.h
> index 897a1f4d2f..f8521780c1 100644
> --- a/bsd-user/freebsd/os-socket.h
> +++ b/bsd-user/freebsd/os-socket.h
> @@ -399,5 +399,289 @@ unimplemented:
>      return ret;
>  }
>  
> +/* getsockopt(2) */
> +static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
> +        abi_ulong optval_addr, abi_ulong optlen)
> +{
> +    abi_long ret;
> +    int len, val;
> +    socklen_t lv;
> +    void *p;
> +
> +    switch (level) {
> +    case TARGET_SOL_SOCKET:
> +        level = SOL_SOCKET;
> +        switch (optname) {
> +
> +        /* These don't just return a single integer */
> +        case TARGET_SO_LINGER:
> +        case TARGET_SO_RCVTIMEO:
> +        case TARGET_SO_SNDTIMEO:
> +        case TARGET_SO_ACCEPTFILTER:
> +            goto unimplemented;
> +
> +        /* Options with 'int' argument.  */
> +        case TARGET_SO_DEBUG:
> +            optname = SO_DEBUG;
> +            goto int_case;
> +
> +        case TARGET_SO_REUSEADDR:
> +            optname = SO_REUSEADDR;
> +            goto int_case;
> +
> +        case TARGET_SO_REUSEPORT:
> +            optname = SO_REUSEPORT;
> +            goto int_case;
> +
> +        case TARGET_SO_TYPE:
> +            optname = SO_TYPE;
> +            goto int_case;
> +
> +        case TARGET_SO_ERROR:
> +            optname = SO_ERROR;
> +            goto int_case;
> +
> +        case TARGET_SO_DONTROUTE:
> +            optname = SO_DONTROUTE;
> +            goto int_case;
> +
> +        case TARGET_SO_BROADCAST:
> +            optname = SO_BROADCAST;
> +            goto int_case;
> +
> +        case TARGET_SO_SNDBUF:
> +            optname = SO_SNDBUF;
> +            goto int_case;
> +
> +        case TARGET_SO_RCVBUF:
> +            optname = SO_RCVBUF;
> +            goto int_case;
> +
> +        case TARGET_SO_KEEPALIVE:
> +            optname = SO_KEEPALIVE;
> +            goto int_case;
> +
> +        case TARGET_SO_OOBINLINE:
> +            optname = SO_OOBINLINE;
> +            goto int_case;
> +
> +        case TARGET_SO_TIMESTAMP:
> +            optname = SO_TIMESTAMP;
> +            goto int_case;
> +
> +        case TARGET_SO_RCVLOWAT:
> +            optname = SO_RCVLOWAT;
> +            goto int_case;
> +
> +        case TARGET_SO_LISTENINCQLEN:
> +            optname = SO_LISTENINCQLEN;
> +            goto int_case;
> +

This duplicates what there is in previous patch.
We should add a target_to_host_sockopt that takes care of this.

> +        default:
> +int_case:
> +            if (get_user_u32(len, optlen)) {
> +                return -TARGET_EFAULT;
> +            }
> +            if (len < 0) {
> +                return -TARGET_EINVAL;
> +            }
> +            lv = sizeof(lv);
> +            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
> +            if (ret < 0) {
> +                return ret;
> +            }
> +            if (len > lv) {
> +                len = lv;
> +            }
> +            if (len == 4) {
> +                if (put_user_u32(val, optval_addr)) {
> +                    return -TARGET_EFAULT;
> +                }
> +            } else {
> +                if (put_user_u8(val, optval_addr)) {
> +                    return -TARGET_EFAULT;
> +                }
> +            }
> +            if (put_user_u32(len, optlen)) {
> +                return -TARGET_EFAULT;
> +            }
> +            break;
> +
> +        }
> +        break;
> +
> +    case IPPROTO_TCP:
> +        /* TCP options all take an 'int' value. */
> +        goto int_case;
> +
> +    case IPPROTO_IP:
> +        switch (optname) {
> +        case IP_OPTIONS:
> +            if (get_user_u32(len, optlen)) {
> +                return -TARGET_EFAULT;
> +            }
> +            lv = (socklen_t)len;
> +            p = lock_user(VERIFY_WRITE, optval_addr, len, 0);
> +            if (p == NULL) {
> +                return -TARGET_EFAULT;
> +            }
> +            ret = get_errno(getsockopt(sockfd, level, optname, p, &lv));
> +            unlock_user(p, optval_addr, len);
> +            if (put_user_u32(lv, optlen)) {
> +                return -TARGET_EFAULT;
> +            }
> +            break;
> +        case IP_HDRINCL:
> +        case IP_TOS:
> +        case IP_TTL:
> +        case IP_RECVOPTS:
> +        case IP_RECVRETOPTS:
> +        case IP_RECVDSTADDR:
> +
> +        case IP_RETOPTS:
> +#if defined(IP_RECVTOS)
> +        case IP_RECVTOS:
> +#endif
> +        case IP_MULTICAST_TTL:
> +        case IP_MULTICAST_LOOP:
> +        case IP_PORTRANGE:
> +        case IP_IPSEC_POLICY:
> +        case IP_ONESBCAST:
> +        case IP_BINDANY:
> +            if (get_user_u32(len, optlen)) {
> +                return -TARGET_EFAULT;
> +            }
> +            if (len < 0) {
> +                return -TARGET_EINVAL;
> +            }
> +            lv = sizeof(lv);
> +            ret = get_errno(getsockopt(sockfd, level, optname,
> +                &val, &lv));
> +            if (ret < 0) {
> +                return ret;
> +            }
> +            if (len < sizeof(int) && len > 0 && val >= 0 &&
> +                val < 255) {
> +                len = 1;
> +                if (put_user_u32(len, optlen) ||
> +                        put_user_u8(val, optval_addr)) {
> +                    return -TARGET_EFAULT;
> +                }
> +            } else {
> +                if (len > sizeof(int)) {
> +                    len = sizeof(int);
> +                }
> +                if (put_user_u32(len, optlen) ||
> +                        put_user_u32(val, optval_addr)) {
> +                    return -TARGET_EFAULT;
> +                }
> +            }
> +            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 */
> +            if (get_user_u32(len, optlen)) {
> +                return -TARGET_EFAULT;
> +            }
> +            if (len < 0) {
> +                return -TARGET_EINVAL;
> +            }
> +            lv = sizeof(lv);
> +            ret = get_errno(getsockopt(sockfd, level, optname,
> +                &val, &lv));
> +            if (ret < 0) {
> +                return ret;
> +            }
> +            if (len < sizeof(int) && len > 0 && val >= 0 &&
> +                val < 255) {
> +                len = 1;
> +                if (put_user_u32(len, optlen) ||
> +                        put_user_u8(val, optval_addr)) {
> +                    return -TARGET_EFAULT;
> +                }
> +            } else {
> +                if (len > sizeof(int)) {
> +                    len = sizeof(int);
> +                }
> +                if (put_user_u32(len, optlen) ||
> +                        put_user_u32(val, optval_addr)) {
> +                    return -TARGET_EFAULT;
> +                }
> +            }
> +            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;
> +
> +    default:
> +unimplemented:
> +        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
> +            level, optname);
> +        ret = -TARGET_EOPNOTSUPP;
> +        break;
> +    }
> +    return ret;
> +}
> +
>  
>  #endif /* BSD_USER_FREEBSD_OS_SOCKET_H */
>
diff mbox series

Patch

diff --git a/bsd-user/freebsd/os-socket.h b/bsd-user/freebsd/os-socket.h
index 897a1f4d2f..f8521780c1 100644
--- a/bsd-user/freebsd/os-socket.h
+++ b/bsd-user/freebsd/os-socket.h
@@ -399,5 +399,289 @@  unimplemented:
     return ret;
 }
 
+/* getsockopt(2) */
+static inline abi_long do_bsd_getsockopt(int sockfd, int level, int optname,
+        abi_ulong optval_addr, abi_ulong optlen)
+{
+    abi_long ret;
+    int len, val;
+    socklen_t lv;
+    void *p;
+
+    switch (level) {
+    case TARGET_SOL_SOCKET:
+        level = SOL_SOCKET;
+        switch (optname) {
+
+        /* These don't just return a single integer */
+        case TARGET_SO_LINGER:
+        case TARGET_SO_RCVTIMEO:
+        case TARGET_SO_SNDTIMEO:
+        case TARGET_SO_ACCEPTFILTER:
+            goto unimplemented;
+
+        /* Options with 'int' argument.  */
+        case TARGET_SO_DEBUG:
+            optname = SO_DEBUG;
+            goto int_case;
+
+        case TARGET_SO_REUSEADDR:
+            optname = SO_REUSEADDR;
+            goto int_case;
+
+        case TARGET_SO_REUSEPORT:
+            optname = SO_REUSEPORT;
+            goto int_case;
+
+        case TARGET_SO_TYPE:
+            optname = SO_TYPE;
+            goto int_case;
+
+        case TARGET_SO_ERROR:
+            optname = SO_ERROR;
+            goto int_case;
+
+        case TARGET_SO_DONTROUTE:
+            optname = SO_DONTROUTE;
+            goto int_case;
+
+        case TARGET_SO_BROADCAST:
+            optname = SO_BROADCAST;
+            goto int_case;
+
+        case TARGET_SO_SNDBUF:
+            optname = SO_SNDBUF;
+            goto int_case;
+
+        case TARGET_SO_RCVBUF:
+            optname = SO_RCVBUF;
+            goto int_case;
+
+        case TARGET_SO_KEEPALIVE:
+            optname = SO_KEEPALIVE;
+            goto int_case;
+
+        case TARGET_SO_OOBINLINE:
+            optname = SO_OOBINLINE;
+            goto int_case;
+
+        case TARGET_SO_TIMESTAMP:
+            optname = SO_TIMESTAMP;
+            goto int_case;
+
+        case TARGET_SO_RCVLOWAT:
+            optname = SO_RCVLOWAT;
+            goto int_case;
+
+        case TARGET_SO_LISTENINCQLEN:
+            optname = SO_LISTENINCQLEN;
+            goto int_case;
+
+        default:
+int_case:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len > lv) {
+                len = lv;
+            }
+            if (len == 4) {
+                if (put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                if (put_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            if (put_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            break;
+
+        }
+        break;
+
+    case IPPROTO_TCP:
+        /* TCP options all take an 'int' value. */
+        goto int_case;
+
+    case IPPROTO_IP:
+        switch (optname) {
+        case IP_OPTIONS:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            lv = (socklen_t)len;
+            p = lock_user(VERIFY_WRITE, optval_addr, len, 0);
+            if (p == NULL) {
+                return -TARGET_EFAULT;
+            }
+            ret = get_errno(getsockopt(sockfd, level, optname, p, &lv));
+            unlock_user(p, optval_addr, len);
+            if (put_user_u32(lv, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            break;
+        case IP_HDRINCL:
+        case IP_TOS:
+        case IP_TTL:
+        case IP_RECVOPTS:
+        case IP_RECVRETOPTS:
+        case IP_RECVDSTADDR:
+
+        case IP_RETOPTS:
+#if defined(IP_RECVTOS)
+        case IP_RECVTOS:
+#endif
+        case IP_MULTICAST_TTL:
+        case IP_MULTICAST_LOOP:
+        case IP_PORTRANGE:
+        case IP_IPSEC_POLICY:
+        case IP_ONESBCAST:
+        case IP_BINDANY:
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname,
+                &val, &lv));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len < sizeof(int) && len > 0 && val >= 0 &&
+                val < 255) {
+                len = 1;
+                if (put_user_u32(len, optlen) ||
+                        put_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                if (len > sizeof(int)) {
+                    len = sizeof(int);
+                }
+                if (put_user_u32(len, optlen) ||
+                        put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            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 */
+            if (get_user_u32(len, optlen)) {
+                return -TARGET_EFAULT;
+            }
+            if (len < 0) {
+                return -TARGET_EINVAL;
+            }
+            lv = sizeof(lv);
+            ret = get_errno(getsockopt(sockfd, level, optname,
+                &val, &lv));
+            if (ret < 0) {
+                return ret;
+            }
+            if (len < sizeof(int) && len > 0 && val >= 0 &&
+                val < 255) {
+                len = 1;
+                if (put_user_u32(len, optlen) ||
+                        put_user_u8(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            } else {
+                if (len > sizeof(int)) {
+                    len = sizeof(int);
+                }
+                if (put_user_u32(len, optlen) ||
+                        put_user_u32(val, optval_addr)) {
+                    return -TARGET_EFAULT;
+                }
+            }
+            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;
+
+    default:
+unimplemented:
+        gemu_log("getsockopt level=%d optname=%d not yet supported\n",
+            level, optname);
+        ret = -TARGET_EOPNOTSUPP;
+        break;
+    }
+    return ret;
+}
+
 
 #endif /* BSD_USER_FREEBSD_OS_SOCKET_H */