1 /* $NetBSD: linux_socket.c,v 1.18 1998/10/04 00:02:43 fvdl 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 64 #include <sys/syscallargs.h> 65 66 #include <compat/linux/common/linux_types.h> 67 #include <compat/linux/common/linux_util.h> 68 #include <compat/linux/common/linux_signal.h> 69 #include <compat/linux/common/linux_ioctl.h> 70 #include <compat/linux/common/linux_socket.h> 71 #include <compat/linux/common/linux_socketcall.h> 72 #include <compat/linux/common/linux_sockio.h> 73 74 #include <compat/linux/linux_syscallargs.h> 75 76 /* 77 * The calls in this file are entered either via the linux_socketcall() 78 * interface or, on the Alpha, as individual syscalls. The 79 * linux_socketcall function does any massaging of arguments so that all 80 * the calls in here need not think that they are anything other 81 * than a normal syscall. 82 */ 83 84 int linux_to_bsd_domain __P((int)); 85 int linux_to_bsd_sopt_level __P((int)); 86 int linux_to_bsd_so_sockopt __P((int)); 87 int linux_to_bsd_ip_sockopt __P((int)); 88 int linux_to_bsd_tcp_sockopt __P((int)); 89 int linux_to_bsd_udp_sockopt __P((int)); 90 91 /* 92 * Convert between Linux and BSD socket domain values 93 */ 94 int 95 linux_to_bsd_domain(ldom) 96 int ldom; 97 { 98 99 switch (ldom) { 100 case LINUX_AF_UNSPEC: 101 return AF_UNSPEC; 102 case LINUX_AF_UNIX: 103 return AF_LOCAL; 104 case LINUX_AF_INET: 105 return AF_INET; 106 case LINUX_AF_AX25: 107 return AF_CCITT; 108 case LINUX_AF_IPX: 109 return AF_IPX; 110 case LINUX_AF_APPLETALK: 111 return AF_APPLETALK; 112 case LINUX_AF_X25: 113 return AF_CCITT; 114 case LINUX_AF_INET6: 115 return AF_INET6; 116 case LINUX_AF_DECnet: 117 return AF_DECnet; 118 case LINUX_AF_NETLINK: 119 return AF_ROUTE; 120 /* NETROM, BRIDGE, ATMPVC, ROSE, NETBEUI, SECURITY, */ 121 /* pseudo_AF_KEY, PACKET, ASH, ECONET, ATMSVC, SNA */ 122 default: 123 return -1; 124 } 125 } 126 127 int 128 linux_sys_socket(p, v, retval) 129 struct proc *p; 130 void *v; 131 register_t *retval; 132 { 133 struct linux_sys_socket_args /* { 134 syscallarg(int) domain; 135 syscallarg(int) type; 136 syscallarg(int) protocol; 137 } */ *uap = v; 138 struct sys_socket_args bsa; 139 140 SCARG(&bsa, protocol) = SCARG(uap, protocol); 141 SCARG(&bsa, type) = SCARG(uap, type); 142 SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain)); 143 if (SCARG(&bsa, domain) == -1) 144 return EINVAL; 145 return sys_socket(p, &bsa, retval); 146 } 147 148 int 149 linux_sys_socketpair(p, v, retval) 150 struct proc *p; 151 void *v; 152 register_t *retval; 153 { 154 struct linux_sys_socketpair_args /* { 155 syscallarg(int) domain; 156 syscallarg(int) type; 157 syscallarg(int) protocol; 158 syscallarg(int *) rsv; 159 } */ *uap = v; 160 struct sys_socketpair_args bsa; 161 162 SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain)); 163 if (SCARG(&bsa, domain) == -1) 164 return EINVAL; 165 SCARG(&bsa, type) = SCARG(uap, type); 166 SCARG(&bsa, protocol) = SCARG(uap, protocol); 167 SCARG(&bsa, rsv) = SCARG(uap, rsv); 168 169 return sys_socketpair(p, &bsa, retval); 170 } 171 172 int 173 linux_sys_sendto(p, v, retval) 174 struct proc *p; 175 void *v; 176 register_t *retval; 177 { 178 struct linux_sys_sendto_args /* { 179 syscallarg(int) s; 180 syscallarg(void *) msg; 181 syscallarg(int) len; 182 syscallarg(int) flags; 183 syscallarg(sockaddr *) to; 184 syscallarg(int) tolen; 185 } */ *uap = v; 186 struct sys_sendto_args bsa; 187 188 SCARG(&bsa, s) = SCARG(uap, s); 189 SCARG(&bsa, buf) = SCARG(uap, msg); 190 SCARG(&bsa, len) = SCARG(uap, len); 191 SCARG(&bsa, flags) = SCARG(uap, flags); 192 SCARG(&bsa, to) = (void *) SCARG(uap, to); 193 SCARG(&bsa, tolen) = SCARG(uap, tolen); 194 195 return sys_sendto(p, &bsa, retval); 196 } 197 198 int 199 linux_sys_recvfrom(p, v, retval) 200 struct proc *p; 201 void *v; 202 register_t *retval; 203 { 204 struct linux_sys_recvfrom_args /* { 205 syscallarg(int) s; 206 syscallarg(void *) buf; 207 syscallarg(int) len; 208 syscallarg(int) flags; 209 syscallarg(struct sockaddr *) from; 210 syscallarg(int *) fromlen; 211 } */ *uap = v; 212 struct compat_43_sys_recvfrom_args bra; 213 214 SCARG(&bra, s) = SCARG(uap, s); 215 SCARG(&bra, buf) = SCARG(uap, buf); 216 SCARG(&bra, len) = SCARG(uap, len); 217 SCARG(&bra, flags) = SCARG(uap, flags); 218 SCARG(&bra, from) = (caddr_t) SCARG(uap, from); 219 SCARG(&bra, fromlenaddr) = SCARG(uap, fromlen); 220 221 return compat_43_sys_recvfrom(p, &bra, retval); 222 } 223 224 /* 225 * Convert socket option level from Linux to NetBSD value. Only SOL_SOCKET 226 * is different, the rest matches IPPROTO_* on both systems. 227 */ 228 int 229 linux_to_bsd_sopt_level(llevel) 230 int llevel; 231 { 232 233 switch (llevel) { 234 case LINUX_SOL_SOCKET: 235 return SOL_SOCKET; 236 case LINUX_SOL_IP: 237 return IPPROTO_IP; 238 case LINUX_SOL_TCP: 239 return IPPROTO_TCP; 240 case LINUX_SOL_UDP: 241 return IPPROTO_UDP; 242 default: 243 return -1; 244 } 245 } 246 247 /* 248 * Convert Linux socket level socket option numbers to NetBSD values. 249 */ 250 int 251 linux_to_bsd_so_sockopt(lopt) 252 int lopt; 253 { 254 255 switch (lopt) { 256 case LINUX_SO_DEBUG: 257 return SO_DEBUG; 258 case LINUX_SO_REUSEADDR: 259 return SO_REUSEADDR; 260 case LINUX_SO_TYPE: 261 return SO_TYPE; 262 case LINUX_SO_ERROR: 263 return SO_ERROR; 264 case LINUX_SO_DONTROUTE: 265 return SO_DONTROUTE; 266 case LINUX_SO_BROADCAST: 267 return SO_BROADCAST; 268 case LINUX_SO_SNDBUF: 269 return SO_SNDBUF; 270 case LINUX_SO_RCVBUF: 271 return SO_RCVBUF; 272 case LINUX_SO_KEEPALIVE: 273 return SO_KEEPALIVE; 274 case LINUX_SO_OOBINLINE: 275 return SO_OOBINLINE; 276 case LINUX_SO_LINGER: 277 return SO_LINGER; 278 case LINUX_SO_PRIORITY: 279 case LINUX_SO_NO_CHECK: 280 default: 281 return -1; 282 } 283 } 284 285 /* 286 * Convert Linux IP level socket option number to NetBSD values. 287 */ 288 int 289 linux_to_bsd_ip_sockopt(lopt) 290 int lopt; 291 { 292 293 switch (lopt) { 294 case LINUX_IP_TOS: 295 return IP_TOS; 296 case LINUX_IP_TTL: 297 return IP_TTL; 298 case LINUX_IP_MULTICAST_TTL: 299 return IP_MULTICAST_TTL; 300 case LINUX_IP_MULTICAST_LOOP: 301 return IP_MULTICAST_LOOP; 302 case LINUX_IP_MULTICAST_IF: 303 return IP_MULTICAST_IF; 304 case LINUX_IP_ADD_MEMBERSHIP: 305 return IP_ADD_MEMBERSHIP; 306 case LINUX_IP_DROP_MEMBERSHIP: 307 return IP_DROP_MEMBERSHIP; 308 default: 309 return -1; 310 } 311 } 312 313 /* 314 * Convert Linux TCP level socket option number to NetBSD values. 315 */ 316 int 317 linux_to_bsd_tcp_sockopt(lopt) 318 int lopt; 319 { 320 321 switch (lopt) { 322 case LINUX_TCP_NODELAY: 323 return TCP_NODELAY; 324 case LINUX_TCP_MAXSEG: 325 return TCP_MAXSEG; 326 default: 327 return -1; 328 } 329 } 330 331 /* 332 * Convert Linux UDP level socket option number to NetBSD values. 333 */ 334 int 335 linux_to_bsd_udp_sockopt(lopt) 336 int lopt; 337 { 338 339 switch (lopt) { 340 default: 341 return -1; 342 } 343 } 344 345 /* 346 * Another reasonably straightforward function: setsockopt(2). 347 * The level and option numbers are converted; the values passed 348 * are not (yet) converted, the ones currently implemented don't 349 * need conversion, as they are the same on both systems. 350 */ 351 int 352 linux_sys_setsockopt(p, v, retval) 353 struct proc *p; 354 void *v; 355 register_t *retval; 356 { 357 struct linux_sys_setsockopt_args /* { 358 syscallarg(int) s; 359 syscallarg(int) level; 360 syscallarg(int) optname; 361 syscallarg(void *) optval; 362 syscallarg(int) optlen; 363 } */ *uap = v; 364 struct sys_setsockopt_args bsa; 365 int name; 366 367 SCARG(&bsa, s) = SCARG(uap, s); 368 SCARG(&bsa, level) = linux_to_bsd_sopt_level(SCARG(uap, level)); 369 SCARG(&bsa, val) = SCARG(uap, optval); 370 SCARG(&bsa, valsize) = SCARG(uap, optlen); 371 372 switch (SCARG(&bsa, level)) { 373 case SOL_SOCKET: 374 name = linux_to_bsd_so_sockopt(SCARG(uap, optname)); 375 break; 376 case IPPROTO_IP: 377 name = linux_to_bsd_ip_sockopt(SCARG(uap, optname)); 378 break; 379 case IPPROTO_TCP: 380 name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname)); 381 break; 382 case IPPROTO_UDP: 383 name = linux_to_bsd_udp_sockopt(SCARG(uap, optname)); 384 break; 385 default: 386 return EINVAL; 387 } 388 389 if (name == -1) 390 return EINVAL; 391 SCARG(&bsa, name) = name; 392 393 return sys_setsockopt(p, &bsa, retval); 394 } 395 396 /* 397 * getsockopt(2) is very much the same as setsockopt(2) (see above) 398 */ 399 int 400 linux_sys_getsockopt(p, v, retval) 401 struct proc *p; 402 void *v; 403 register_t *retval; 404 { 405 struct linux_sys_getsockopt_args /* { 406 syscallarg(int) s; 407 syscallarg(int) level; 408 syscallarg(int) optname; 409 syscallarg(void *) optval; 410 syscallarg(int *) optlen; 411 } */ *uap = v; 412 struct sys_getsockopt_args bga; 413 int name; 414 415 SCARG(&bga, s) = SCARG(uap, s); 416 SCARG(&bga, level) = linux_to_bsd_sopt_level(SCARG(uap, level)); 417 SCARG(&bga, val) = SCARG(uap, optval); 418 SCARG(&bga, avalsize) = SCARG(uap, optlen); 419 420 switch (SCARG(&bga, level)) { 421 case SOL_SOCKET: 422 name = linux_to_bsd_so_sockopt(SCARG(uap, optname)); 423 break; 424 case IPPROTO_IP: 425 name = linux_to_bsd_ip_sockopt(SCARG(uap, optname)); 426 break; 427 case IPPROTO_TCP: 428 name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname)); 429 break; 430 case IPPROTO_UDP: 431 name = linux_to_bsd_udp_sockopt(SCARG(uap, optname)); 432 break; 433 default: 434 return EINVAL; 435 } 436 437 if (name == -1) 438 return EINVAL; 439 SCARG(&bga, name) = name; 440 441 return sys_getsockopt(p, &bga, retval); 442 } 443 444 int 445 linux_ioctl_socket(p, uap, retval) 446 register struct proc *p; 447 register struct linux_sys_ioctl_args /* { 448 syscallarg(int) fd; 449 syscallarg(u_long) com; 450 syscallarg(caddr_t) data; 451 } */ *uap; 452 register_t *retval; 453 { 454 u_long com; 455 struct sys_ioctl_args ia; 456 457 com = SCARG(uap, com); 458 retval[0] = 0; 459 460 switch (com) { 461 case LINUX_SIOCGIFCONF: 462 SCARG(&ia, com) = OSIOCGIFCONF; 463 break; 464 case LINUX_SIOCGIFFLAGS: 465 SCARG(&ia, com) = SIOCGIFFLAGS; 466 break; 467 case LINUX_SIOCGIFADDR: 468 SCARG(&ia, com) = OSIOCGIFADDR; 469 break; 470 case LINUX_SIOCGIFDSTADDR: 471 SCARG(&ia, com) = OSIOCGIFDSTADDR; 472 break; 473 case LINUX_SIOCGIFBRDADDR: 474 SCARG(&ia, com) = OSIOCGIFBRDADDR; 475 break; 476 case LINUX_SIOCGIFNETMASK: 477 SCARG(&ia, com) = OSIOCGIFNETMASK; 478 break; 479 case LINUX_SIOCADDMULTI: 480 SCARG(&ia, com) = SIOCADDMULTI; 481 break; 482 case LINUX_SIOCDELMULTI: 483 SCARG(&ia, com) = SIOCDELMULTI; 484 break; 485 default: 486 return EINVAL; 487 } 488 489 SCARG(&ia, fd) = SCARG(uap, fd); 490 SCARG(&ia, data) = SCARG(uap, data); 491 return sys_ioctl(p, &ia, retval); 492 } 493