1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/systm.h> 29 #include <sys/cred.h> 30 #include <sys/errno.h> 31 #include <sys/socket.h> 32 #include <sys/ksocket.h> 33 #include <sys/debug.h> 34 #include <sys/kmem.h> 35 #include <unistd.h> 36 #include <errno.h> 37 #include <umem.h> 38 39 #define _KSOCKET_MAGIC 0xabcdef09 40 41 #define KSOCKET_VALID(ks) (ks->kso_magic == _KSOCKET_MAGIC) 42 #define KSTOSO(ks) (ks->kso_fd) 43 44 #ifndef SS_CLOSING 45 #define SS_CLOSING 0x00010000 46 #endif 47 48 /* 49 * NB: you can't cast this into a sonode like you can with a normal 50 * ksocket_t, but no correct code should ever do that anyway. 51 * The ksocket_t type is opaque to prevent exactly that. 52 */ 53 struct __ksocket { 54 uint32_t kso_magic; 55 uint32_t kso_count; 56 uint32_t kso_state; 57 int kso_fd; 58 kmutex_t kso_lock; 59 kcondvar_t kso_closing_cv; 60 }; 61 62 static umem_cache_t *ksocket_cache = NULL; 63 64 /*ARGSUSED*/ 65 static int 66 _ksocket_ctor(void *buf, void *arg, int flags) 67 { 68 ksocket_t sock = buf; 69 70 bzero(sock, sizeof (*sock)); 71 mutex_init(&sock->kso_lock, NULL, MUTEX_DEFAULT, NULL); 72 cv_init(&sock->kso_closing_cv, NULL, CV_DEFAULT, NULL); 73 return (0); 74 } 75 76 /*ARGSUSED*/ 77 static void 78 _ksocket_dtor(void *buf, void *arg) 79 { 80 ksocket_t sock = buf; 81 82 mutex_destroy(&sock->kso_lock); 83 cv_destroy(&sock->kso_closing_cv); 84 } 85 86 #pragma init(_ksocket_init) 87 int 88 _ksocket_init(void) 89 { 90 ksocket_cache = umem_cache_create("ksocket", 91 sizeof (struct __ksocket), 0, 92 _ksocket_ctor, _ksocket_dtor, NULL, NULL, NULL, 0); 93 VERIFY(ksocket_cache != NULL); 94 return (0); 95 } 96 97 #pragma fini(_ksocket_fini) 98 int 99 _ksocket_fini(void) 100 { 101 umem_cache_destroy(ksocket_cache); 102 return (0); 103 } 104 105 static ksocket_t 106 _ksocket_create(int fd) 107 { 108 ksocket_t ks; 109 110 ks = umem_cache_alloc(ksocket_cache, 0); 111 VERIFY(ks != NULL); 112 ks->kso_magic = _KSOCKET_MAGIC; 113 ks->kso_count = 1; 114 ks->kso_fd = fd; 115 return (ks); 116 } 117 118 static void 119 _ksocket_destroy(ksocket_t ks) 120 { 121 ASSERT(ks->kso_count == 1); 122 umem_cache_free(ksocket_cache, ks); 123 } 124 125 int 126 ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags, 127 struct cred *cr) 128 { 129 int fd; 130 ksocket_t ks; 131 132 /* All Solaris components should pass a cred for this operation. */ 133 ASSERT(cr != NULL); 134 135 ASSERT(flags == KSOCKET_SLEEP || flags == KSOCKET_NOSLEEP); 136 137 fd = socket(domain, type, protocol); 138 if (fd < 0) { 139 *ksp = NULL; 140 return (errno); 141 } 142 143 ks = _ksocket_create(fd); 144 *ksp = ks; 145 return (0); 146 } 147 148 /* 149 * This is marked NODIRECT so the main program linking with this library 150 * can provide its own "bind helper" function. See: fksmbd_ksock.c 151 */ 152 /* ARGSUSED */ 153 int 154 ksocket_bind_helper(int fd, struct sockaddr *addr, uint_t addrlen) 155 { 156 return (EACCES); 157 } 158 159 int 160 ksocket_bind(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen, 161 struct cred *cr) 162 { 163 int err = 0; 164 165 /* All Solaris components should pass a cred for this operation. */ 166 ASSERT(cr != NULL); 167 168 if (!KSOCKET_VALID(ks)) 169 return (ENOTSOCK); 170 171 if (bind(KSTOSO(ks), addr, addrlen) != 0) 172 err = errno; 173 174 if (err == EACCES) { 175 err = ksocket_bind_helper(KSTOSO(ks), addr, addrlen); 176 } 177 178 return (err); 179 } 180 181 int 182 ksocket_listen(ksocket_t ks, int backlog, struct cred *cr) 183 { 184 /* All Solaris components should pass a cred for this operation. */ 185 ASSERT(cr != NULL); 186 187 if (!KSOCKET_VALID(ks)) 188 return (ENOTSOCK); 189 190 if (listen(KSTOSO(ks), backlog) != 0) 191 return (errno); 192 193 return (0); 194 } 195 196 int 197 ksocket_accept(ksocket_t ks, struct sockaddr *addr, 198 socklen_t *addrlenp, ksocket_t *nks, struct cred *cr) 199 { 200 int fd; 201 202 /* All Solaris components should pass a cred for this operation. */ 203 ASSERT(cr != NULL); 204 205 *nks = NULL; 206 207 if (!KSOCKET_VALID(ks)) 208 return (ENOTSOCK); 209 210 if (addr != NULL && addrlenp == NULL) 211 return (EFAULT); 212 213 fd = accept(KSTOSO(ks), addr, addrlenp); 214 if (fd < 0) 215 return (errno); 216 217 *nks = _ksocket_create(fd); 218 219 return (0); 220 } 221 222 int 223 ksocket_connect(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen, 224 struct cred *cr) 225 { 226 /* All Solaris components should pass a cred for this operation. */ 227 ASSERT(cr != NULL); 228 229 if (!KSOCKET_VALID(ks)) 230 return (ENOTSOCK); 231 232 if (connect(KSTOSO(ks), addr, addrlen) != 0) 233 return (errno); 234 235 return (0); 236 } 237 238 int 239 ksocket_send(ksocket_t ks, void *msg, size_t msglen, int flags, 240 size_t *sent, struct cred *cr) 241 { 242 ssize_t error; 243 244 /* All Solaris components should pass a cred for this operation. */ 245 ASSERT(cr != NULL); 246 247 if (!KSOCKET_VALID(ks)) { 248 if (sent != NULL) 249 *sent = 0; 250 return (ENOTSOCK); 251 } 252 253 error = send(KSTOSO(ks), msg, msglen, flags); 254 if (error < 0) { 255 if (sent != NULL) 256 *sent = 0; 257 return (errno); 258 } 259 260 if (sent != NULL) 261 *sent = (size_t)error; 262 return (0); 263 } 264 265 int 266 ksocket_sendto(ksocket_t ks, void *msg, size_t msglen, int flags, 267 struct sockaddr *name, socklen_t namelen, size_t *sent, struct cred *cr) 268 { 269 ssize_t error; 270 271 /* All Solaris components should pass a cred for this operation. */ 272 ASSERT(cr != NULL); 273 274 if (!KSOCKET_VALID(ks)) { 275 if (sent != NULL) 276 *sent = 0; 277 return (ENOTSOCK); 278 } 279 280 error = sendto(KSTOSO(ks), msg, msglen, flags, name, namelen); 281 if (error < 0) { 282 if (sent != NULL) 283 *sent = 0; 284 return (errno); 285 } 286 287 if (sent != NULL) 288 *sent = (size_t)error; 289 return (0); 290 } 291 292 int 293 ksocket_sendmsg(ksocket_t ks, struct nmsghdr *msg, int flags, 294 size_t *sent, struct cred *cr) 295 { 296 ssize_t error; 297 298 /* All Solaris components should pass a cred for this operation. */ 299 ASSERT(cr != NULL); 300 301 if (!KSOCKET_VALID(ks)) { 302 if (sent != NULL) 303 *sent = 0; 304 return (ENOTSOCK); 305 } 306 307 error = sendmsg(KSTOSO(ks), msg, flags); 308 if (error < 0) { 309 if (sent != NULL) 310 *sent = 0; 311 return (errno); 312 } 313 314 if (sent != NULL) 315 *sent = (size_t)error; 316 return (0); 317 } 318 319 int 320 ksocket_recv(ksocket_t ks, void *msg, size_t msglen, int flags, 321 size_t *recvd, struct cred *cr) 322 { 323 ssize_t error; 324 325 /* All Solaris components should pass a cred for this operation. */ 326 ASSERT(cr != NULL); 327 328 if (!KSOCKET_VALID(ks)) { 329 if (recvd != NULL) 330 *recvd = 0; 331 return (ENOTSOCK); 332 } 333 334 error = recv(KSTOSO(ks), msg, msglen, flags); 335 if (error < 0) { 336 if (recvd != NULL) 337 *recvd = 0; 338 return (errno); 339 } 340 341 if (recvd != NULL) 342 *recvd = (size_t)error; 343 return (0); 344 } 345 346 int 347 ksocket_recvfrom(ksocket_t ks, void *msg, size_t msglen, int flags, 348 struct sockaddr *name, socklen_t *namelen, size_t *recvd, struct cred *cr) 349 { 350 ssize_t error; 351 352 /* All Solaris components should pass a cred for this operation. */ 353 ASSERT(cr != NULL); 354 355 if (!KSOCKET_VALID(ks)) { 356 if (recvd != NULL) 357 *recvd = 0; 358 return (ENOTSOCK); 359 } 360 361 error = recvfrom(KSTOSO(ks), msg, msglen, flags, name, namelen); 362 if (error != 0) { 363 if (recvd != NULL) 364 *recvd = 0; 365 return (errno); 366 } 367 368 if (recvd != NULL) 369 *recvd = (ssize_t)error; 370 return (0); 371 } 372 373 int 374 ksocket_recvmsg(ksocket_t ks, struct nmsghdr *msg, int flags, size_t *recvd, 375 struct cred *cr) 376 { 377 ssize_t error; 378 379 /* All Solaris components should pass a cred for this operation. */ 380 ASSERT(cr != NULL); 381 382 if (!KSOCKET_VALID(ks)) { 383 if (recvd != NULL) 384 *recvd = 0; 385 return (ENOTSOCK); 386 } 387 388 error = recvmsg(KSTOSO(ks), msg, flags); 389 if (error < 0) { 390 if (recvd != NULL) 391 *recvd = 0; 392 return (errno); 393 } 394 395 if (recvd != NULL) 396 *recvd = (size_t)error; 397 return (0); 398 } 399 400 int 401 ksocket_shutdown(ksocket_t ks, int how, struct cred *cr) 402 { 403 /* All Solaris components should pass a cred for this operation. */ 404 ASSERT(cr != NULL); 405 406 if (!KSOCKET_VALID(ks)) 407 return (ENOTSOCK); 408 409 if (shutdown(KSTOSO(ks), how) != 0) 410 return (errno); 411 412 return (0); 413 } 414 415 int 416 ksocket_close(ksocket_t ks, struct cred *cr) 417 { 418 int fd; 419 420 /* All Solaris components should pass a cred for this operation. */ 421 ASSERT(cr != NULL); 422 423 mutex_enter(&ks->kso_lock); 424 425 if (!KSOCKET_VALID(ks)) { 426 mutex_exit(&ks->kso_lock); 427 return (ENOTSOCK); 428 } 429 430 ks->kso_state |= SS_CLOSING; 431 432 /* 433 * The real ksocket wakes up everything. 434 * It seems the only way we can do that 435 * is to go ahead and close the FD. 436 */ 437 fd = ks->kso_fd; 438 ks->kso_fd = -1; 439 (void) close(fd); 440 441 while (ks->kso_count > 1) 442 cv_wait(&ks->kso_closing_cv, &ks->kso_lock); 443 444 mutex_exit(&ks->kso_lock); 445 _ksocket_destroy(ks); 446 447 return (0); 448 } 449 450 int 451 ksocket_getsockname(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen, 452 struct cred *cr) 453 { 454 /* All Solaris components should pass a cred for this operation. */ 455 ASSERT(cr != NULL); 456 457 if (!KSOCKET_VALID(ks)) 458 return (ENOTSOCK); 459 460 if (addrlen == NULL || (addr == NULL && *addrlen != 0)) 461 return (EFAULT); 462 463 if (getsockname(KSTOSO(ks), addr, addrlen) != 0) 464 return (errno); 465 466 return (0); 467 } 468 469 int 470 ksocket_getpeername(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen, 471 struct cred *cr) 472 { 473 /* All Solaris components should pass a cred for this operation. */ 474 ASSERT(cr != NULL); 475 476 if (!KSOCKET_VALID(ks)) 477 return (ENOTSOCK); 478 479 if (addrlen == NULL || (addr == NULL && *addrlen != 0)) 480 return (EFAULT); 481 482 if (getpeername(KSTOSO(ks), addr, addrlen) != 0) 483 return (errno); 484 485 return (0); 486 } 487 488 int 489 ksocket_setsockopt(ksocket_t ks, int level, int optname, const void *optval, 490 int optlen, struct cred *cr) 491 { 492 /* All Solaris components should pass a cred for this operation. */ 493 ASSERT(cr != NULL); 494 495 if (!KSOCKET_VALID(ks)) 496 return (ENOTSOCK); 497 498 if (optval == NULL) 499 optlen = 0; 500 501 if (setsockopt(KSTOSO(ks), level, optname, optval, optlen) != 0) 502 return (errno); 503 504 return (0); 505 } 506 507 int 508 ksocket_ioctl(ksocket_t ks, int cmd, intptr_t arg, int *rvp, struct cred *cr) 509 { 510 int rval; 511 512 /* All Solaris components should pass a cred for this operation. */ 513 ASSERT(cr != NULL); 514 515 if (!KSOCKET_VALID(ks)) 516 return (ENOTSOCK); 517 518 rval = ioctl(KSTOSO(ks), cmd, arg); 519 if (rvp != NULL) 520 *rvp = rval; 521 522 if (rval != 0) 523 rval = errno; 524 525 return (rval); 526 } 527 528 void 529 ksocket_hold(ksocket_t ks) 530 { 531 if (!mutex_owned(&ks->kso_lock)) { 532 mutex_enter(&ks->kso_lock); 533 ks->kso_count++; 534 mutex_exit(&ks->kso_lock); 535 } else 536 ks->kso_count++; 537 } 538 539 void 540 ksocket_rele(ksocket_t ks) 541 { 542 /* 543 * When so_count equals 1 means no thread working on this ksocket 544 */ 545 VERIFY3U(ks->kso_count, >, 1); 546 547 if (!mutex_owned(&ks->kso_lock)) { 548 mutex_enter(&ks->kso_lock); 549 if (--ks->kso_count == 1) 550 cv_signal(&ks->kso_closing_cv); 551 mutex_exit(&ks->kso_lock); 552 } else { 553 if (--ks->kso_count == 1) 554 cv_signal(&ks->kso_closing_cv); 555 } 556 } 557