static int linux_socket(struct linux_socket_args *args, int *res) { struct linux_socket_args linux_args; struct sockopt sopt; int error, domain, optval; error = copyin(args, &linux_args, sizeof(linux_args)); if (error) return (error); domain = linux_to_bsd_domain(linux_args.domain); if (domain == -1) return (EINVAL); error = kern_socket(domain, linux_args.type, linux_args.protocol, res); /* Copy back the return value from socket() */ if (error == 0 && linux_args.type == SOCK_RAW && (linux_args.protocol == IPPROTO_RAW || linux_args.protocol == 0) && linux_args.domain == AF_INET) { /* It's a raw IP socket: set the IP_HDRINCL option. */ optval = 1; sopt.sopt_dir = SOPT_SET; sopt.sopt_level = IPPROTO_IP; sopt.sopt_name = IP_HDRINCL; sopt.sopt_val = &optval; sopt.sopt_valsize = sizeof(optval); sopt.sopt_td = NULL; /* We ignore any error returned by setsockopt() */ kern_setsockopt(*res, &sopt); } return (error); }
static int linux_socket(struct thread *td, struct linux_socket_args *args) { struct socket_args /* { int domain; int type; int protocol; } */ bsd_args; int retval_socket, socket_flags; bsd_args.protocol = args->protocol; socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK; if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK)) return (EINVAL); bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK; if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX) return (EINVAL); bsd_args.domain = linux_to_bsd_domain(args->domain); if (bsd_args.domain == -1) return (EAFNOSUPPORT); retval_socket = socket(td, &bsd_args); if (retval_socket) return (retval_socket); retval_socket = linux_set_socket_flags(td, td->td_retval[0], socket_flags); if (retval_socket) { (void)kern_close(td, td->td_retval[0]); goto out; } if (bsd_args.type == SOCK_RAW && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0) && bsd_args.domain == PF_INET) { /* It's a raw IP socket: set the IP_HDRINCL option. */ int hdrincl; hdrincl = 1; /* We ignore any error returned by kern_setsockopt() */ kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL, &hdrincl, UIO_SYSSPACE, sizeof(hdrincl)); } #ifdef INET6 /* * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default * and some apps depend on this. So, set V6ONLY to 0 for Linux apps. * For simplicity we do this unconditionally of the net.inet6.ip6.v6only * sysctl value. */ if (bsd_args.domain == PF_INET6) { int v6only; v6only = 0; /* We ignore any error returned by setsockopt() */ kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY, &v6only, UIO_SYSSPACE, sizeof(v6only)); } #endif out: return (retval_socket); }