Home | History | Annotate | Line # | Download | only in common
linux32_socket.c revision 1.5.12.3
      1 /*	$NetBSD: linux32_socket.c,v 1.5.12.3 2008/06/23 04:30:54 wrstuden Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *	This product includes software developed by Emmanuel Dreyfus
     17  * 4. The name of the author may not be used to endorse or promote
     18  *    products derived from this software without specific prior written
     19  *    permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
     22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
     25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 
     36 __KERNEL_RCSID(0, "$NetBSD: linux32_socket.c,v 1.5.12.3 2008/06/23 04:30:54 wrstuden Exp $");
     37 
     38 #include <sys/types.h>
     39 #include <sys/param.h>
     40 #include <sys/fstypes.h>
     41 #include <sys/signal.h>
     42 #include <sys/dirent.h>
     43 #include <sys/kernel.h>
     44 #include <sys/fcntl.h>
     45 #include <sys/select.h>
     46 #include <sys/proc.h>
     47 #include <sys/ucred.h>
     48 #include <sys/swap.h>
     49 #include <sys/file.h>
     50 #include <sys/vnode.h>
     51 #include <sys/filedesc.h>
     52 
     53 #include <machine/types.h>
     54 
     55 #include <net/if.h>
     56 
     57 #include <sys/syscallargs.h>
     58 
     59 #include <compat/netbsd32/netbsd32.h>
     60 #include <compat/netbsd32/netbsd32_conv.h>
     61 #include <compat/netbsd32/netbsd32_syscallargs.h>
     62 #include <compat/sys/sockio.h>
     63 
     64 #include <compat/linux/common/linux_types.h>
     65 #include <compat/linux/common/linux_types.h>
     66 #include <compat/linux/common/linux_signal.h>
     67 #include <compat/linux/common/linux_machdep.h>
     68 #include <compat/linux/common/linux_misc.h>
     69 #include <compat/linux/common/linux_oldolduname.h>
     70 #include <compat/linux/common/linux_ioctl.h>
     71 #include <compat/linux/common/linux_sockio.h>
     72 #include <compat/linux/linux_syscallargs.h>
     73 
     74 #include <compat/linux32/common/linux32_types.h>
     75 #include <compat/linux32/common/linux32_signal.h>
     76 #include <compat/linux32/common/linux32_machdep.h>
     77 #include <compat/linux32/common/linux32_sysctl.h>
     78 #include <compat/linux32/common/linux32_socketcall.h>
     79 #include <compat/linux32/common/linux32_ioctl.h>
     80 #include <compat/linux32/linux32_syscallargs.h>
     81 
     82 int
     83 linux32_sys_socketpair(struct lwp *l, const struct linux32_sys_socketpair_args *uap, register_t *retval)
     84 {
     85 	/* {
     86 		syscallarg(int) domain;
     87 		syscallarg(int) type;
     88 		syscallarg(int) protocol;
     89 		syscallarg(netbsd32_intp) rsv;
     90 	} */
     91 	struct linux_sys_socketpair_args ua;
     92 
     93 	NETBSD32TO64_UAP(domain);
     94 	NETBSD32TO64_UAP(type);
     95 	NETBSD32TO64_UAP(protocol);
     96 	NETBSD32TOP_UAP(rsv, int)
     97 
     98 	return linux_sys_socketpair(l, &ua, retval);
     99 }
    100 
    101 int
    102 linux32_sys_sendto(struct lwp *l, const struct linux32_sys_sendto_args *uap, register_t *retval)
    103 {
    104 	/* {
    105 		syscallarg(int) s;
    106 		syscallarg(netbsd32_voidp) msg;
    107 		syscallarg(int) len;
    108 		syscallarg(int) flags;
    109 		syscallarg(netbsd32_osockaddrp_t) to;
    110 		syscallarg(int) tolen;
    111 	} */
    112 	struct linux_sys_sendto_args ua;
    113 
    114 	NETBSD32TO64_UAP(s);
    115 	NETBSD32TOP_UAP(msg, void);
    116 	NETBSD32TO64_UAP(len);
    117 	NETBSD32TO64_UAP(flags);
    118 	NETBSD32TOP_UAP(to, struct osockaddr);
    119 	NETBSD32TO64_UAP(tolen);
    120 
    121 	return linux_sys_sendto(l, &ua, retval);
    122 }
    123 
    124 
    125 int
    126 linux32_sys_recvfrom(struct lwp *l, const struct linux32_sys_recvfrom_args *uap, register_t *retval)
    127 {
    128 	/* {
    129 		syscallarg(int) s;
    130 		syscallarg(netbsd32_voidp) buf;
    131 		syscallarg(netbsd32_size_t) len;
    132 		syscallarg(int) flags;
    133 		syscallarg(netbsd32_osockaddrp_t) from;
    134 		syscallarg(netbsd32_intp) fromlenaddr;
    135 	} */
    136 	struct linux_sys_recvfrom_args ua;
    137 
    138 	NETBSD32TO64_UAP(s);
    139 	NETBSD32TOP_UAP(buf, void);
    140 	NETBSD32TO64_UAP(len);
    141 	NETBSD32TO64_UAP(flags);
    142 	NETBSD32TOP_UAP(from, struct osockaddr);
    143 	NETBSD32TOP_UAP(fromlenaddr, unsigned int);
    144 
    145 	return linux_sys_recvfrom(l, &ua, retval);
    146 }
    147 
    148 int
    149 linux32_sys_setsockopt(struct lwp *l, const struct linux32_sys_setsockopt_args *uap, register_t *retval)
    150 {
    151 	/* {
    152 		syscallarg(int) s;
    153 		syscallarg(int) level;
    154 		syscallarg(int) optname;
    155 		syscallarg(netbsd32_voidp) optval;
    156 		syscallarg(int) optlen;
    157 	} */
    158 	struct linux_sys_setsockopt_args ua;
    159 
    160 	NETBSD32TO64_UAP(s);
    161 	NETBSD32TO64_UAP(level);
    162 	NETBSD32TO64_UAP(optname);
    163 	NETBSD32TOP_UAP(optval, void);
    164 	NETBSD32TO64_UAP(optlen);
    165 
    166 	return linux_sys_setsockopt(l, &ua, retval);
    167 }
    168 
    169 
    170 int
    171 linux32_sys_getsockopt(struct lwp *l, const struct linux32_sys_getsockopt_args *uap, register_t *retval)
    172 {
    173 	/* {
    174 		syscallarg(int) s;
    175 		syscallarg(int) level;
    176 		syscallarg(int) optname;
    177 		syscallarg(netbsd32_voidp) optval;
    178 		syscallarg(netbsd32_intp) optlen;
    179 	} */
    180 	struct linux_sys_getsockopt_args ua;
    181 
    182 	NETBSD32TO64_UAP(s);
    183 	NETBSD32TO64_UAP(level);
    184 	NETBSD32TO64_UAP(optname);
    185 	NETBSD32TOP_UAP(optval, void);
    186 	NETBSD32TOP_UAP(optlen, int);
    187 
    188 	return linux_sys_getsockopt(l, &ua, retval);
    189 }
    190 
    191 int
    192 linux32_sys_socket(struct lwp *l, const struct linux32_sys_socket_args *uap, register_t *retval)
    193 {
    194 	/* {
    195 		syscallarg(int) domain;
    196 		syscallarg(int) type;
    197 		syscallarg(int) protocol;
    198 	} */
    199 	struct linux_sys_socket_args ua;
    200 
    201 	NETBSD32TO64_UAP(domain);
    202 	NETBSD32TO64_UAP(type);
    203 	NETBSD32TO64_UAP(protocol);
    204 
    205 	return linux_sys_socket(l, &ua, retval);
    206 }
    207 
    208 int
    209 linux32_sys_bind(struct lwp *l, const struct linux32_sys_bind_args *uap, register_t *retval)
    210 {
    211 	/* {
    212 		syscallarg(int) s;
    213 		syscallarg(netbsd32_osockaddrp_t) name;
    214 		syscallarg(int) namelen;
    215 	} */
    216 	struct linux_sys_bind_args ua;
    217 
    218 	NETBSD32TO64_UAP(s);
    219 	NETBSD32TOP_UAP(name, struct osockaddr)
    220 	NETBSD32TO64_UAP(namelen);
    221 
    222 	return linux_sys_bind(l, &ua, retval);
    223 }
    224 
    225 int
    226 linux32_sys_connect(struct lwp *l, const struct linux32_sys_connect_args *uap, register_t *retval)
    227 {
    228 	/* {
    229 		syscallarg(int) s;
    230 		syscallarg(netbsd32_osockaddrp_t) name;
    231 		syscallarg(int) namelen;
    232 	} */
    233 	struct linux_sys_connect_args ua;
    234 
    235 	NETBSD32TO64_UAP(s);
    236 	NETBSD32TOP_UAP(name, struct osockaddr)
    237 	NETBSD32TO64_UAP(namelen);
    238 
    239 #ifdef DEBUG_LINUX
    240 	printf("linux32_sys_connect: s = %d, name = %p, namelen = %d\n",
    241 		SCARG(&ua, s), SCARG(&ua, name), SCARG(&ua, namelen));
    242 #endif
    243 
    244 	return linux_sys_connect(l, &ua, retval);
    245 }
    246 
    247 int
    248 linux32_sys_accept(struct lwp *l, const struct linux32_sys_accept_args *uap, register_t *retval)
    249 {
    250 	/* {
    251 		syscallarg(int) s;
    252 		syscallarg(netbsd32_osockaddrp_t) name;
    253 		syscallarg(netbsd32_intp) anamelen;
    254 	} */
    255 	struct linux_sys_accept_args ua;
    256 
    257 	NETBSD32TO64_UAP(s);
    258 	NETBSD32TOP_UAP(name, struct osockaddr)
    259 	NETBSD32TOP_UAP(anamelen, int);
    260 
    261 	return linux_sys_accept(l, &ua, retval);
    262 }
    263 
    264 int
    265 linux32_sys_getpeername(struct lwp *l, const struct linux32_sys_getpeername_args *uap, register_t *retval)
    266 {
    267 	/* {
    268 		syscallarg(int) fdes;
    269 		syscallarg(netbsd32_sockaddrp_t) asa;
    270 		syscallarg(netbsd32_intp) alen;
    271 	} */
    272 	struct linux_sys_getpeername_args ua;
    273 
    274 	NETBSD32TO64_UAP(fdes);
    275 	NETBSD32TOP_UAP(asa, struct sockaddr)
    276 	NETBSD32TOP_UAP(alen, int);
    277 
    278 	return linux_sys_getpeername(l, &ua, retval);
    279 }
    280 
    281 int
    282 linux32_sys_getsockname(struct lwp *l, const struct linux32_sys_getsockname_args *uap, register_t *retval)
    283 {
    284 	/* {
    285 		syscallarg(int) fdec;
    286 		syscallarg(netbsd32_charp) asa;
    287 		syscallarg(netbsd32_intp) alen;
    288 	} */
    289 	struct linux_sys_getsockname_args ua;
    290 
    291 	NETBSD32TO64_UAP(fdec);
    292 	NETBSD32TOP_UAP(asa, char)
    293 	NETBSD32TOP_UAP(alen, int);
    294 
    295 	return linux_sys_getsockname(l, &ua, retval);
    296 }
    297 
    298 int
    299 linux32_sys_sendmsg(struct lwp *l, const struct linux32_sys_sendmsg_args *uap, register_t *retval)
    300 {
    301 	/* {
    302 		syscallarg(int) s;
    303 		syscallarg(netbsd32_msghdrp_t) msg;
    304 		syscallarg(int) flags;
    305 	} */
    306 	struct linux_sys_sendmsg_args ua;
    307 
    308 	NETBSD32TO64_UAP(s);
    309 	NETBSD32TOP_UAP(msg, struct msghdr);
    310 	NETBSD32TO64_UAP(flags);
    311 
    312 	return linux_sys_sendmsg(l, &ua, retval);
    313 }
    314 
    315 int
    316 linux32_sys_recvmsg(struct lwp *l, const struct linux32_sys_recvmsg_args *uap, register_t *retval)
    317 {
    318 	/* {
    319 		syscallarg(int) s;
    320 		syscallarg(netbsd32_msghdrp_t) msg;
    321 		syscallarg(int) flags;
    322 	} */
    323 	struct linux_sys_recvmsg_args ua;
    324 
    325 	NETBSD32TO64_UAP(s);
    326 	NETBSD32TOP_UAP(msg, struct msghdr);
    327 	NETBSD32TO64_UAP(flags);
    328 
    329 	return linux_sys_recvmsg(l, &ua, retval);
    330 }
    331 
    332 int
    333 linux32_sys_send(struct lwp *l, const struct linux32_sys_send_args *uap, register_t *retval)
    334 {
    335 	/* {
    336 		syscallarg(int) s;
    337 		syscallarg(netbsd32_voidp) buf;
    338 		syscallarg(int) len;
    339 		syscallarg(int) flags;
    340 	} */
    341 	struct sys_sendto_args ua;
    342 
    343 	NETBSD32TO64_UAP(s);
    344 	NETBSD32TOP_UAP(buf, void);
    345 	NETBSD32TO64_UAP(len);
    346 	NETBSD32TO64_UAP(flags);
    347 	SCARG(&ua, to) = NULL;
    348 	SCARG(&ua, tolen) = 0;
    349 
    350 	return sys_sendto(l, &ua, retval);
    351 }
    352 
    353 int
    354 linux32_sys_recv(struct lwp *l, const struct linux32_sys_recv_args *uap, register_t *retval)
    355 {
    356 	/* {
    357 		syscallarg(int) s;
    358 		syscallarg(netbsd32_voidp) buf;
    359 		syscallarg(int) len;
    360 		syscallarg(int) flags;
    361 	} */
    362 	struct sys_recvfrom_args ua;
    363 
    364 	NETBSD32TO64_UAP(s);
    365 	NETBSD32TOP_UAP(buf, void);
    366 	NETBSD32TO64_UAP(len);
    367 	NETBSD32TO64_UAP(flags);
    368 	SCARG(&ua, from) = NULL;
    369 	SCARG(&ua, fromlenaddr) = NULL;
    370 
    371 	return sys_recvfrom(l, &ua, retval);
    372 }
    373 
    374 int
    375 linux32_ioctl_socket(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval)
    376 {
    377 	/* {
    378 		syscallarg(int) fd;
    379 		syscallarg(u_long) com;
    380 		syscallarg(void *) data;
    381 	} */
    382 	u_long com;
    383 	int error = 0, isdev = 0, dosys = 1;
    384 	struct netbsd32_ioctl_args ia;
    385 	file_t *fp;
    386 	struct vnode *vp;
    387 	int (*ioctlf)(file_t *, u_long, void *);
    388 	struct ioctl_pt pt;
    389 
    390 	if ((fp = fd_getfile(SCARG(uap, fd))) == NULL)
    391 		return (EBADF);
    392 
    393 	if (fp->f_type == DTYPE_VNODE) {
    394 		vp = (struct vnode *)fp->f_data;
    395 		isdev = vp->v_type == VCHR;
    396 	}
    397 
    398 	/*
    399 	 * Don't try to interpret socket ioctl calls that are done
    400 	 * on a device filedescriptor, just pass them through, to
    401 	 * emulate Linux behaviour. Use PTIOCLINUX so that the
    402 	 * device will only handle these if it's prepared to do
    403 	 * so, to avoid unexpected things from happening.
    404 	 */
    405 	if (isdev) {
    406 		dosys = 0;
    407 		ioctlf = fp->f_ops->fo_ioctl;
    408 		pt.com = SCARG(uap, com);
    409 		pt.data = (void *)NETBSD32PTR64(SCARG(uap, data));
    410 		error = ioctlf(fp, PTIOCLINUX, &pt);
    411 		/*
    412 		 * XXX hack: if the function returns EJUSTRETURN,
    413 		 * it has stuffed a sysctl return value in pt.data.
    414 		 */
    415 		if (error == EJUSTRETURN) {
    416 			retval[0] = (register_t)pt.data;
    417 			error = 0;
    418 		}
    419 		goto out;
    420 	}
    421 
    422 	com = SCARG(uap, com);
    423 	retval[0] = 0;
    424 
    425 	switch (com) {
    426 	case LINUX_SIOCGIFCONF:
    427 		SCARG(&ia, com) = OOSIOCGIFCONF;
    428 		break;
    429 	case LINUX_SIOCGIFFLAGS:
    430 		SCARG(&ia, com) = OSIOCGIFFLAGS;
    431 		break;
    432 	case LINUX_SIOCSIFFLAGS:
    433 		SCARG(&ia, com) = OSIOCSIFFLAGS;
    434 		break;
    435 	case LINUX_SIOCGIFADDR:
    436 		SCARG(&ia, com) = OOSIOCGIFADDR;
    437 		break;
    438 	case LINUX_SIOCGIFDSTADDR:
    439 		SCARG(&ia, com) = OOSIOCGIFDSTADDR;
    440 		break;
    441 	case LINUX_SIOCGIFBRDADDR:
    442 		SCARG(&ia, com) = OOSIOCGIFBRDADDR;
    443 		break;
    444 	case LINUX_SIOCGIFNETMASK:
    445 		SCARG(&ia, com) = OOSIOCGIFNETMASK;
    446 		break;
    447 	case LINUX_SIOCADDMULTI:
    448 		SCARG(&ia, com) = OSIOCADDMULTI;
    449 		break;
    450 	case LINUX_SIOCDELMULTI:
    451 		SCARG(&ia, com) = OSIOCDELMULTI;
    452 		break;
    453 #ifdef notyet
    454 	case LINUX_SIOCGIFHWADDR:
    455 		error = linux_getifhwaddr(l, retval, SCARG(uap, fd),
    456 		    SCARG(uap, data));
    457 		dosys = 0;
    458 		break;
    459 #endif
    460 	default:
    461 		error = EINVAL;
    462 	}
    463 
    464  out:
    465  	fd_putfile(SCARG(uap, fd));
    466 
    467 	if (error == 0 && dosys) {
    468 		SCARG(&ia, fd) = SCARG(uap, fd);
    469 		SCARG(&ia, data) = SCARG(uap, data);
    470 		error = netbsd32_ioctl(curlwp, &ia, retval);
    471 	}
    472 
    473 	return error;
    474 }
    475