1 /* $NetBSD: linux_socket.c,v 1.20 1999/05/05 20:01:03 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden and Eric Haszlakiewicz. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Functions in multiarch: 41 * linux_sys_socketcall : linux_socketcall.c 42 */ 43 44 #include <sys/param.h> 45 #include <sys/kernel.h> 46 #include <sys/systm.h> 47 #include <sys/buf.h> 48 #include <sys/malloc.h> 49 #include <sys/ioctl.h> 50 #include <sys/tty.h> 51 #include <sys/file.h> 52 #include <sys/filedesc.h> 53 #include <sys/select.h> 54 #include <sys/socket.h> 55 #include <sys/socketvar.h> 56 #include <net/if.h> 57 #include <netinet/in.h> 58 #include <netinet/tcp.h> 59 #include <sys/mount.h> 60 #include <sys/proc.h> 61 #include <sys/vnode.h> 62 #include <sys/device.h> 63 #include <sys/protosw.h> 64 65 #include <sys/syscallargs.h> 66 67 #include <compat/linux/common/linux_types.h> 68 #include <compat/linux/common/linux_util.h> 69 #include <compat/linux/common/linux_signal.h> 70 #include <compat/linux/common/linux_ioctl.h> 71 #include <compat/linux/common/linux_socket.h> 72 #include <compat/linux/common/linux_socketcall.h> 73 #include <compat/linux/common/linux_sockio.h> 74 75 #include <compat/linux/linux_syscallargs.h> 76 77 /* 78 * The calls in this file are entered either via the linux_socketcall() 79 * interface or, on the Alpha, as individual syscalls. The 80 * linux_socketcall function does any massaging of arguments so that all 81 * the calls in here need not think that they are anything other 82 * than a normal syscall. 83 */ 84 85 int linux_to_bsd_domain __P((int)); 86 int linux_to_bsd_sopt_level __P((int)); 87 int linux_to_bsd_so_sockopt __P((int)); 88 int linux_to_bsd_ip_sockopt __P((int)); 89 int linux_to_bsd_tcp_sockopt __P((int)); 90 int linux_to_bsd_udp_sockopt __P((int)); 91 92 /* 93 * Convert between Linux and BSD socket domain values 94 */ 95 int 96 linux_to_bsd_domain(ldom) 97 int ldom; 98 { 99 100 switch (ldom) { 101 case LINUX_AF_UNSPEC: 102 return AF_UNSPEC; 103 case LINUX_AF_UNIX: 104 return AF_LOCAL; 105 case LINUX_AF_INET: 106 return AF_INET; 107 case LINUX_AF_AX25: 108 return AF_CCITT; 109 case LINUX_AF_IPX: 110 return AF_IPX; 111 case LINUX_AF_APPLETALK: 112 return AF_APPLETALK; 113 case LINUX_AF_X25: 114 return AF_CCITT; 115 case LINUX_AF_INET6: 116 return AF_INET6; 117 case LINUX_AF_DECnet: 118 return AF_DECnet; 119 case LINUX_AF_NETLINK: 120 return AF_ROUTE; 121 /* NETROM, BRIDGE, ATMPVC, ROSE, NETBEUI, SECURITY, */ 122 /* pseudo_AF_KEY, PACKET, ASH, ECONET, ATMSVC, SNA */ 123 default: 124 return -1; 125 } 126 } 127 128 int 129 linux_sys_socket(p, v, retval) 130 struct proc *p; 131 void *v; 132 register_t *retval; 133 { 134 struct linux_sys_socket_args /* { 135 syscallarg(int) domain; 136 syscallarg(int) type; 137 syscallarg(int) protocol; 138 } */ *uap = v; 139 struct sys_socket_args bsa; 140 141 SCARG(&bsa, protocol) = SCARG(uap, protocol); 142 SCARG(&bsa, type) = SCARG(uap, type); 143 SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain)); 144 if (SCARG(&bsa, domain) == -1) 145 return EINVAL; 146 return sys_socket(p, &bsa, retval); 147 } 148 149 int 150 linux_sys_socketpair(p, v, retval) 151 struct proc *p; 152 void *v; 153 register_t *retval; 154 { 155 struct linux_sys_socketpair_args /* { 156 syscallarg(int) domain; 157 syscallarg(int) type; 158 syscallarg(int) protocol; 159 syscallarg(int *) rsv; 160 } */ *uap = v; 161 struct sys_socketpair_args bsa; 162 163 SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain)); 164 if (SCARG(&bsa, domain) == -1) 165 return EINVAL; 166 SCARG(&bsa, type) = SCARG(uap, type); 167 SCARG(&bsa, protocol) = SCARG(uap, protocol); 168 SCARG(&bsa, rsv) = SCARG(uap, rsv); 169 170 return sys_socketpair(p, &bsa, retval); 171 } 172 173 int 174 linux_sys_sendto(p, v, retval) 175 struct proc *p; 176 void *v; 177 register_t *retval; 178 { 179 struct linux_sys_sendto_args /* { 180 syscallarg(int) s; 181 syscallarg(void *) msg; 182 syscallarg(int) len; 183 syscallarg(int) flags; 184 syscallarg(sockaddr *) to; 185 syscallarg(int) tolen; 186 } */ *uap = v; 187 struct sys_sendto_args bsa; 188 189 SCARG(&bsa, s) = SCARG(uap, s); 190 SCARG(&bsa, buf) = SCARG(uap, msg); 191 SCARG(&bsa, len) = SCARG(uap, len); 192 SCARG(&bsa, flags) = SCARG(uap, flags); 193 SCARG(&bsa, to) = (void *) SCARG(uap, to); 194 SCARG(&bsa, tolen) = SCARG(uap, tolen); 195 196 return sys_sendto(p, &bsa, retval); 197 } 198 199 int 200 linux_sys_recvfrom(p, v, retval) 201 struct proc *p; 202 void *v; 203 register_t *retval; 204 { 205 struct linux_sys_recvfrom_args /* { 206 syscallarg(int) s; 207 syscallarg(void *) buf; 208 syscallarg(int) len; 209 syscallarg(int) flags; 210 syscallarg(struct sockaddr *) from; 211 syscallarg(int *) fromlen; 212 } */ *uap = v; 213 struct compat_43_sys_recvfrom_args bra; 214 215 SCARG(&bra, s) = SCARG(uap, s); 216 SCARG(&bra, buf) = SCARG(uap, buf); 217 SCARG(&bra, len) = SCARG(uap, len); 218 SCARG(&bra, flags) = SCARG(uap, flags); 219 SCARG(&bra, from) = (caddr_t) SCARG(uap, from); 220 SCARG(&bra, fromlenaddr) = SCARG(uap, fromlen); 221 222 return compat_43_sys_recvfrom(p, &bra, retval); 223 } 224 225 /* 226 * Convert socket option level from Linux to NetBSD value. Only SOL_SOCKET 227 * is different, the rest matches IPPROTO_* on both systems. 228 */ 229 int 230 linux_to_bsd_sopt_level(llevel) 231 int llevel; 232 { 233 234 switch (llevel) { 235 case LINUX_SOL_SOCKET: 236 return SOL_SOCKET; 237 case LINUX_SOL_IP: 238 return IPPROTO_IP; 239 case LINUX_SOL_TCP: 240 return IPPROTO_TCP; 241 case LINUX_SOL_UDP: 242 return IPPROTO_UDP; 243 default: 244 return -1; 245 } 246 } 247 248 /* 249 * Convert Linux socket level socket option numbers to NetBSD values. 250 */ 251 int 252 linux_to_bsd_so_sockopt(lopt) 253 int lopt; 254 { 255 256 switch (lopt) { 257 case LINUX_SO_DEBUG: 258 return SO_DEBUG; 259 case LINUX_SO_REUSEADDR: 260 return SO_REUSEADDR; 261 case LINUX_SO_TYPE: 262 return SO_TYPE; 263 case LINUX_SO_ERROR: 264 return SO_ERROR; 265 case LINUX_SO_DONTROUTE: 266 return SO_DONTROUTE; 267 case LINUX_SO_BROADCAST: 268 return SO_BROADCAST; 269 case LINUX_SO_SNDBUF: 270 return SO_SNDBUF; 271 case LINUX_SO_RCVBUF: 272 return SO_RCVBUF; 273 case LINUX_SO_KEEPALIVE: 274 return SO_KEEPALIVE; 275 case LINUX_SO_OOBINLINE: 276 return SO_OOBINLINE; 277 case LINUX_SO_LINGER: 278 return SO_LINGER; 279 case LINUX_SO_PRIORITY: 280 case LINUX_SO_NO_CHECK: 281 default: 282 return -1; 283 } 284 } 285 286 /* 287 * Convert Linux IP level socket option number to NetBSD values. 288 */ 289 int 290 linux_to_bsd_ip_sockopt(lopt) 291 int lopt; 292 { 293 294 switch (lopt) { 295 case LINUX_IP_TOS: 296 return IP_TOS; 297 case LINUX_IP_TTL: 298 return IP_TTL; 299 case LINUX_IP_MULTICAST_TTL: 300 return IP_MULTICAST_TTL; 301 case LINUX_IP_MULTICAST_LOOP: 302 return IP_MULTICAST_LOOP; 303 case LINUX_IP_MULTICAST_IF: 304 return IP_MULTICAST_IF; 305 case LINUX_IP_ADD_MEMBERSHIP: 306 return IP_ADD_MEMBERSHIP; 307 case LINUX_IP_DROP_MEMBERSHIP: 308 return IP_DROP_MEMBERSHIP; 309 default: 310 return -1; 311 } 312 } 313 314 /* 315 * Convert Linux TCP level socket option number to NetBSD values. 316 */ 317 int 318 linux_to_bsd_tcp_sockopt(lopt) 319 int lopt; 320 { 321 322 switch (lopt) { 323 case LINUX_TCP_NODELAY: 324 return TCP_NODELAY; 325 case LINUX_TCP_MAXSEG: 326 return TCP_MAXSEG; 327 default: 328 return -1; 329 } 330 } 331 332 /* 333 * Convert Linux UDP level socket option number to NetBSD values. 334 */ 335 int 336 linux_to_bsd_udp_sockopt(lopt) 337 int lopt; 338 { 339 340 switch (lopt) { 341 default: 342 return -1; 343 } 344 } 345 346 /* 347 * Another reasonably straightforward function: setsockopt(2). 348 * The level and option numbers are converted; the values passed 349 * are not (yet) converted, the ones currently implemented don't 350 * need conversion, as they are the same on both systems. 351 */ 352 int 353 linux_sys_setsockopt(p, v, retval) 354 struct proc *p; 355 void *v; 356 register_t *retval; 357 { 358 struct linux_sys_setsockopt_args /* { 359 syscallarg(int) s; 360 syscallarg(int) level; 361 syscallarg(int) optname; 362 syscallarg(void *) optval; 363 syscallarg(int) optlen; 364 } */ *uap = v; 365 struct sys_setsockopt_args bsa; 366 int name; 367 368 SCARG(&bsa, s) = SCARG(uap, s); 369 SCARG(&bsa, level) = linux_to_bsd_sopt_level(SCARG(uap, level)); 370 SCARG(&bsa, val) = SCARG(uap, optval); 371 SCARG(&bsa, valsize) = SCARG(uap, optlen); 372 373 switch (SCARG(&bsa, level)) { 374 case SOL_SOCKET: 375 name = linux_to_bsd_so_sockopt(SCARG(uap, optname)); 376 break; 377 case IPPROTO_IP: 378 name = linux_to_bsd_ip_sockopt(SCARG(uap, optname)); 379 break; 380 case IPPROTO_TCP: 381 name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname)); 382 break; 383 case IPPROTO_UDP: 384 name = linux_to_bsd_udp_sockopt(SCARG(uap, optname)); 385 break; 386 default: 387 return EINVAL; 388 } 389 390 if (name == -1) 391 return EINVAL; 392 SCARG(&bsa, name) = name; 393 394 return sys_setsockopt(p, &bsa, retval); 395 } 396 397 /* 398 * getsockopt(2) is very much the same as setsockopt(2) (see above) 399 */ 400 int 401 linux_sys_getsockopt(p, v, retval) 402 struct proc *p; 403 void *v; 404 register_t *retval; 405 { 406 struct linux_sys_getsockopt_args /* { 407 syscallarg(int) s; 408 syscallarg(int) level; 409 syscallarg(int) optname; 410 syscallarg(void *) optval; 411 syscallarg(int *) optlen; 412 } */ *uap = v; 413 struct sys_getsockopt_args bga; 414 int name; 415 416 SCARG(&bga, s) = SCARG(uap, s); 417 SCARG(&bga, level) = linux_to_bsd_sopt_level(SCARG(uap, level)); 418 SCARG(&bga, val) = SCARG(uap, optval); 419 SCARG(&bga, avalsize) = SCARG(uap, optlen); 420 421 switch (SCARG(&bga, level)) { 422 case SOL_SOCKET: 423 name = linux_to_bsd_so_sockopt(SCARG(uap, optname)); 424 break; 425 case IPPROTO_IP: 426 name = linux_to_bsd_ip_sockopt(SCARG(uap, optname)); 427 break; 428 case IPPROTO_TCP: 429 name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname)); 430 break; 431 case IPPROTO_UDP: 432 name = linux_to_bsd_udp_sockopt(SCARG(uap, optname)); 433 break; 434 default: 435 return EINVAL; 436 } 437 438 if (name == -1) 439 return EINVAL; 440 SCARG(&bga, name) = name; 441 442 return sys_getsockopt(p, &bga, retval); 443 } 444 445 int 446 linux_ioctl_socket(p, uap, retval) 447 register struct proc *p; 448 register struct linux_sys_ioctl_args /* { 449 syscallarg(int) fd; 450 syscallarg(u_long) com; 451 syscallarg(caddr_t) data; 452 } */ *uap; 453 register_t *retval; 454 { 455 u_long com; 456 struct sys_ioctl_args ia; 457 458 com = SCARG(uap, com); 459 retval[0] = 0; 460 461 switch (com) { 462 case LINUX_SIOCGIFCONF: 463 SCARG(&ia, com) = OSIOCGIFCONF; 464 break; 465 case LINUX_SIOCGIFFLAGS: 466 SCARG(&ia, com) = SIOCGIFFLAGS; 467 break; 468 case LINUX_SIOCGIFADDR: 469 SCARG(&ia, com) = OSIOCGIFADDR; 470 break; 471 case LINUX_SIOCGIFDSTADDR: 472 SCARG(&ia, com) = OSIOCGIFDSTADDR; 473 break; 474 case LINUX_SIOCGIFBRDADDR: 475 SCARG(&ia, com) = OSIOCGIFBRDADDR; 476 break; 477 case LINUX_SIOCGIFNETMASK: 478 SCARG(&ia, com) = OSIOCGIFNETMASK; 479 break; 480 case LINUX_SIOCADDMULTI: 481 SCARG(&ia, com) = SIOCADDMULTI; 482 break; 483 case LINUX_SIOCDELMULTI: 484 SCARG(&ia, com) = SIOCDELMULTI; 485 break; 486 default: 487 return EINVAL; 488 } 489 490 SCARG(&ia, fd) = SCARG(uap, fd); 491 SCARG(&ia, data) = SCARG(uap, data); 492 return sys_ioctl(p, &ia, retval); 493 } 494 495 int 496 linux_sys_connect(p, v, retval) 497 register struct proc *p; 498 void *v; 499 register_t *retval; 500 { 501 int error; 502 503 register struct sys_connect_args /* { 504 syscallarg(int) s; 505 syscallarg(const struct sockaddr *) name; 506 syscallarg(unsigned int) namelen; 507 } */ *uap = v; 508 509 error = sys_connect (p, v, retval); 510 511 if (error == EISCONN) { 512 struct file *fp; 513 register struct socket *so; 514 int s, state, prflags; 515 516 /* getsock() will use the descriptor for us */ 517 if (getsock(p->p_fd, SCARG(uap, s), &fp) != 0) 518 return EISCONN; 519 520 s = splsoftnet(); 521 so = (struct socket *)fp->f_data; 522 state = so->so_state; 523 prflags = so->so_proto->pr_flags; 524 splx(s); 525 FILE_UNUSE(fp, p); 526 /* 527 * We should only let this call succeed once per 528 * non-blocking connect; however we don't have 529 * a convenient place to keep that state.. 530 */ 531 if ((state & SS_NBIO) && (state & SS_ISCONNECTED) && 532 (prflags & PR_CONNREQUIRED)) 533 return 0; 534 } 535 536 return error; 537 } 538