1 /* 2 * Copyright (c) 1982 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)uipc_usrreq.c 6.19 (Berkeley) 01/13/86 7 */ 8 9 #include "param.h" 10 #include "dir.h" 11 #include "user.h" 12 #include "mbuf.h" 13 #include "domain.h" 14 #include "protosw.h" 15 #include "socket.h" 16 #include "socketvar.h" 17 #include "unpcb.h" 18 #include "un.h" 19 #include "inode.h" 20 #include "file.h" 21 #include "stat.h" 22 23 /* 24 * Unix communications domain. 25 * 26 * TODO: 27 * SEQPACKET, RDM 28 * rethink name space problems 29 * need a proper out-of-band 30 */ 31 struct sockaddr sun_noname = { AF_UNIX }; 32 ino_t unp_ino; /* prototype for fake inode numbers */ 33 34 /*ARGSUSED*/ 35 uipc_usrreq(so, req, m, nam, rights) 36 struct socket *so; 37 int req; 38 struct mbuf *m, *nam, *rights; 39 { 40 struct unpcb *unp = sotounpcb(so); 41 register struct socket *so2; 42 int error = 0; 43 44 if (req == PRU_CONTROL) 45 return (EOPNOTSUPP); 46 if (req != PRU_SEND && rights && rights->m_len) { 47 error = EOPNOTSUPP; 48 goto release; 49 } 50 if (unp == 0 && req != PRU_ATTACH) { 51 error = EINVAL; 52 goto release; 53 } 54 switch (req) { 55 56 case PRU_ATTACH: 57 if (unp) { 58 error = EISCONN; 59 break; 60 } 61 error = unp_attach(so); 62 break; 63 64 case PRU_DETACH: 65 unp_detach(unp); 66 break; 67 68 case PRU_BIND: 69 error = unp_bind(unp, nam); 70 break; 71 72 case PRU_LISTEN: 73 if (unp->unp_inode == 0) 74 error = EINVAL; 75 break; 76 77 case PRU_CONNECT: 78 error = unp_connect(so, nam); 79 break; 80 81 case PRU_CONNECT2: 82 error = unp_connect2(so, (struct mbuf *)0, 83 (struct socket *)nam); 84 break; 85 86 case PRU_DISCONNECT: 87 unp_disconnect(unp); 88 break; 89 90 case PRU_ACCEPT: 91 /* 92 * Pass back name of connected socket, 93 * if it was bound and we are still connected 94 * (our peer may have closed already!). 95 */ 96 if (unp->unp_conn && unp->unp_conn->unp_addr) { 97 nam->m_len = unp->unp_conn->unp_addr->m_len; 98 bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 99 mtod(nam, caddr_t), (unsigned)nam->m_len); 100 } else { 101 nam->m_len = sizeof(sun_noname); 102 *(mtod(nam, struct sockaddr *)) = sun_noname; 103 } 104 break; 105 106 case PRU_SHUTDOWN: 107 socantsendmore(so); 108 unp_usrclosed(unp); 109 break; 110 111 case PRU_RCVD: 112 switch (so->so_type) { 113 114 case SOCK_DGRAM: 115 panic("uipc 1"); 116 /*NOTREACHED*/ 117 118 case SOCK_STREAM: 119 #define rcv (&so->so_rcv) 120 #define snd (&so2->so_snd) 121 if (unp->unp_conn == 0) 122 break; 123 so2 = unp->unp_conn->unp_socket; 124 /* 125 * Adjust backpressure on sender 126 * and wakeup any waiting to write. 127 */ 128 snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; 129 unp->unp_mbcnt = rcv->sb_mbcnt; 130 snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; 131 unp->unp_cc = rcv->sb_cc; 132 sowwakeup(so2); 133 #undef snd 134 #undef rcv 135 break; 136 137 default: 138 panic("uipc 2"); 139 } 140 break; 141 142 case PRU_SEND: 143 if (rights) { 144 error = unp_internalize(rights); 145 if (error) 146 break; 147 } 148 switch (so->so_type) { 149 150 case SOCK_DGRAM: { 151 struct sockaddr *from; 152 153 if (nam) { 154 if (unp->unp_conn) { 155 error = EISCONN; 156 break; 157 } 158 error = unp_connect(so, nam); 159 if (error) 160 break; 161 } else { 162 if (unp->unp_conn == 0) { 163 error = ENOTCONN; 164 break; 165 } 166 } 167 so2 = unp->unp_conn->unp_socket; 168 if (unp->unp_addr) 169 from = mtod(unp->unp_addr, struct sockaddr *); 170 else 171 from = &sun_noname; 172 if (sbspace(&so2->so_rcv) > 0 && 173 sbappendaddr(&so2->so_rcv, from, m, rights)) { 174 sorwakeup(so2); 175 m = 0; 176 } else 177 error = ENOBUFS; 178 if (nam) 179 unp_disconnect(unp); 180 break; 181 } 182 183 case SOCK_STREAM: 184 #define rcv (&so2->so_rcv) 185 #define snd (&so->so_snd) 186 if (so->so_state & SS_CANTSENDMORE) { 187 error = EPIPE; 188 break; 189 } 190 if (unp->unp_conn == 0) 191 panic("uipc 3"); 192 so2 = unp->unp_conn->unp_socket; 193 /* 194 * Send to paired receive port, and then reduce 195 * send buffer hiwater marks to maintain backpressure. 196 * Wake up readers. 197 */ 198 if (rights) 199 sbappendrights(rcv, m, rights); 200 else 201 sbappend(rcv, m); 202 snd->sb_mbmax -= 203 rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; 204 unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; 205 snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; 206 unp->unp_conn->unp_cc = rcv->sb_cc; 207 sorwakeup(so2); 208 m = 0; 209 #undef snd 210 #undef rcv 211 break; 212 213 default: 214 panic("uipc 4"); 215 } 216 break; 217 218 case PRU_ABORT: 219 unp_drop(unp, ECONNABORTED); 220 break; 221 222 case PRU_SENSE: 223 ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 224 if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 225 so2 = unp->unp_conn->unp_socket; 226 ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 227 } 228 ((struct stat *) m)->st_dev = NODEV; 229 if (unp->unp_ino == 0) 230 unp->unp_ino = unp_ino++; 231 ((struct stat *) m)->st_ino = unp->unp_ino; 232 return (0); 233 234 case PRU_RCVOOB: 235 return (EOPNOTSUPP); 236 237 case PRU_SENDOOB: 238 error = EOPNOTSUPP; 239 break; 240 241 case PRU_SOCKADDR: 242 break; 243 244 case PRU_PEERADDR: 245 break; 246 247 case PRU_SLOWTIMO: 248 break; 249 250 default: 251 panic("piusrreq"); 252 } 253 release: 254 if (m) 255 m_freem(m); 256 return (error); 257 } 258 259 /* 260 * Both send and receive buffers are allocated PIPSIZ bytes of buffering 261 * for stream sockets, although the total for sender and receiver is 262 * actually only PIPSIZ. 263 * Datagram sockets really use the sendspace as the maximum datagram size, 264 * and don't really want to reserve the sendspace. Their recvspace should 265 * be large enough for at least one max-size datagram plus address. 266 */ 267 #define PIPSIZ 4096 268 int unpst_sendspace = PIPSIZ; 269 int unpst_recvspace = PIPSIZ; 270 int unpdg_sendspace = 2*1024; /* really max datagram size */ 271 int unpdg_recvspace = 4*1024; 272 273 int unp_rights; /* file descriptors in flight */ 274 275 unp_attach(so) 276 struct socket *so; 277 { 278 register struct mbuf *m; 279 register struct unpcb *unp; 280 int error; 281 282 switch (so->so_type) { 283 284 case SOCK_STREAM: 285 error = soreserve(so, unpst_sendspace, unpst_recvspace); 286 break; 287 288 case SOCK_DGRAM: 289 error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 290 break; 291 } 292 if (error) 293 return (error); 294 m = m_getclr(M_DONTWAIT, MT_PCB); 295 if (m == NULL) 296 return (ENOBUFS); 297 unp = mtod(m, struct unpcb *); 298 so->so_pcb = (caddr_t)unp; 299 unp->unp_socket = so; 300 return (0); 301 } 302 303 unp_detach(unp) 304 register struct unpcb *unp; 305 { 306 307 if (unp->unp_inode) { 308 unp->unp_inode->i_socket = 0; 309 irele(unp->unp_inode); 310 unp->unp_inode = 0; 311 } 312 if (unp->unp_conn) 313 unp_disconnect(unp); 314 while (unp->unp_refs) 315 unp_drop(unp->unp_refs, ECONNRESET); 316 soisdisconnected(unp->unp_socket); 317 unp->unp_socket->so_pcb = 0; 318 m_freem(unp->unp_addr); 319 (void) m_free(dtom(unp)); 320 if (unp_rights) 321 unp_gc(); 322 } 323 324 unp_bind(unp, nam) 325 struct unpcb *unp; 326 struct mbuf *nam; 327 { 328 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 329 register struct inode *ip; 330 register struct nameidata *ndp = &u.u_nd; 331 int error; 332 333 ndp->ni_dirp = soun->sun_path; 334 if (unp->unp_inode != NULL || nam->m_len == MLEN) 335 return (EINVAL); 336 *(mtod(nam, caddr_t) + nam->m_len) = 0; 337 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 338 ndp->ni_nameiop = CREATE | FOLLOW; 339 ndp->ni_segflg = UIO_SYSSPACE; 340 ip = namei(ndp); 341 if (ip) { 342 iput(ip); 343 return (EADDRINUSE); 344 } 345 if (error = u.u_error) { 346 u.u_error = 0; /* XXX */ 347 return (error); 348 } 349 ip = maknode(IFSOCK | 0777, ndp); 350 if (ip == NULL) { 351 error = u.u_error; /* XXX */ 352 u.u_error = 0; /* XXX */ 353 return (error); 354 } 355 ip->i_socket = unp->unp_socket; 356 unp->unp_inode = ip; 357 unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); 358 iunlock(ip); /* but keep reference */ 359 return (0); 360 } 361 362 unp_connect(so, nam) 363 struct socket *so; 364 struct mbuf *nam; 365 { 366 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 367 register struct inode *ip; 368 int error; 369 register struct socket *so2; 370 register struct nameidata *ndp = &u.u_nd; 371 372 ndp->ni_dirp = soun->sun_path; 373 if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 374 return (EMSGSIZE); 375 *(mtod(nam, caddr_t) + nam->m_len) = 0; 376 ndp->ni_nameiop = LOOKUP | FOLLOW; 377 ndp->ni_segflg = UIO_SYSSPACE; 378 ip = namei(ndp); 379 if (ip == 0) { 380 error = u.u_error; 381 u.u_error = 0; 382 return (error); /* XXX */ 383 } 384 if (access(ip, IWRITE)) { 385 error = u.u_error; 386 u.u_error = 0; /* XXX */ 387 goto bad; 388 } 389 if ((ip->i_mode&IFMT) != IFSOCK) { 390 error = ENOTSOCK; 391 goto bad; 392 } 393 so2 = ip->i_socket; 394 if (so2 == 0) { 395 error = ECONNREFUSED; 396 goto bad; 397 } 398 if (so->so_type != so2->so_type) { 399 error = EPROTOTYPE; 400 goto bad; 401 } 402 if (so->so_proto->pr_flags & PR_CONNREQUIRED && 403 ((so2->so_options&SO_ACCEPTCONN) == 0 || 404 (so2 = sonewconn(so2)) == 0)) { 405 error = ECONNREFUSED; 406 goto bad; 407 } 408 error = unp_connect2(so, nam, so2); 409 bad: 410 iput(ip); 411 return (error); 412 } 413 414 unp_connect2(so, sonam, so2) 415 register struct socket *so; 416 struct mbuf *sonam; 417 register struct socket *so2; 418 { 419 register struct unpcb *unp = sotounpcb(so); 420 register struct unpcb *unp2; 421 422 if (so2->so_type != so->so_type) 423 return (EPROTOTYPE); 424 unp2 = sotounpcb(so2); 425 unp->unp_conn = unp2; 426 switch (so->so_type) { 427 428 case SOCK_DGRAM: 429 unp->unp_nextref = unp2->unp_refs; 430 unp2->unp_refs = unp; 431 soisconnected(so); 432 break; 433 434 case SOCK_STREAM: 435 unp2->unp_conn = unp; 436 soisconnected(so2); 437 soisconnected(so); 438 break; 439 440 default: 441 panic("unp_connect2"); 442 } 443 return (0); 444 } 445 446 unp_disconnect(unp) 447 struct unpcb *unp; 448 { 449 register struct unpcb *unp2 = unp->unp_conn; 450 451 if (unp2 == 0) 452 return; 453 unp->unp_conn = 0; 454 switch (unp->unp_socket->so_type) { 455 456 case SOCK_DGRAM: 457 if (unp2->unp_refs == unp) 458 unp2->unp_refs = unp->unp_nextref; 459 else { 460 unp2 = unp2->unp_refs; 461 for (;;) { 462 if (unp2 == 0) 463 panic("unp_disconnect"); 464 if (unp2->unp_nextref == unp) 465 break; 466 unp2 = unp2->unp_nextref; 467 } 468 unp2->unp_nextref = unp->unp_nextref; 469 } 470 unp->unp_nextref = 0; 471 unp->unp_socket->so_state &= ~SS_ISCONNECTED; 472 break; 473 474 case SOCK_STREAM: 475 soisdisconnected(unp->unp_socket); 476 unp2->unp_conn = 0; 477 soisdisconnected(unp2->unp_socket); 478 break; 479 } 480 } 481 482 #ifdef notdef 483 unp_abort(unp) 484 struct unpcb *unp; 485 { 486 487 unp_detach(unp); 488 } 489 #endif 490 491 /*ARGSUSED*/ 492 unp_usrclosed(unp) 493 struct unpcb *unp; 494 { 495 496 } 497 498 unp_drop(unp, errno) 499 struct unpcb *unp; 500 int errno; 501 { 502 struct socket *so = unp->unp_socket; 503 504 so->so_error = errno; 505 unp_disconnect(unp); 506 if (so->so_head) { 507 so->so_pcb = (caddr_t) 0; 508 m_freem(unp->unp_addr); 509 (void) m_free(dtom(unp)); 510 sofree(so); 511 } 512 } 513 514 #ifdef notdef 515 unp_drain() 516 { 517 518 } 519 #endif 520 521 unp_externalize(rights) 522 struct mbuf *rights; 523 { 524 int newfds = rights->m_len / sizeof (int); 525 register int i; 526 register struct file **rp = mtod(rights, struct file **); 527 register struct file *fp; 528 int f; 529 530 if (newfds > ufavail()) { 531 for (i = 0; i < newfds; i++) { 532 fp = *rp; 533 unp_discard(fp); 534 *rp++ = 0; 535 } 536 return (EMSGSIZE); 537 } 538 for (i = 0; i < newfds; i++) { 539 f = ufalloc(0); 540 if (f < 0) 541 panic("unp_externalize"); 542 fp = *rp; 543 u.u_ofile[f] = fp; 544 fp->f_msgcount--; 545 unp_rights--; 546 *(int *)rp++ = f; 547 } 548 return (0); 549 } 550 551 unp_internalize(rights) 552 struct mbuf *rights; 553 { 554 register struct file **rp; 555 int oldfds = rights->m_len / sizeof (int); 556 register int i; 557 register struct file *fp; 558 559 rp = mtod(rights, struct file **); 560 for (i = 0; i < oldfds; i++) 561 if (getf(*(int *)rp++) == 0) 562 return (EBADF); 563 rp = mtod(rights, struct file **); 564 for (i = 0; i < oldfds; i++) { 565 fp = getf(*(int *)rp); 566 *rp++ = fp; 567 fp->f_count++; 568 fp->f_msgcount++; 569 unp_rights++; 570 } 571 return (0); 572 } 573 574 int unp_defer, unp_gcing; 575 int unp_mark(); 576 extern struct domain unixdomain; 577 578 unp_gc() 579 { 580 register struct file *fp; 581 register struct socket *so; 582 583 if (unp_gcing) 584 return; 585 unp_gcing = 1; 586 restart: 587 unp_defer = 0; 588 for (fp = file; fp < fileNFILE; fp++) 589 fp->f_flag &= ~(FMARK|FDEFER); 590 do { 591 for (fp = file; fp < fileNFILE; fp++) { 592 if (fp->f_count == 0) 593 continue; 594 if (fp->f_flag & FDEFER) { 595 fp->f_flag &= ~FDEFER; 596 unp_defer--; 597 } else { 598 if (fp->f_flag & FMARK) 599 continue; 600 if (fp->f_count == fp->f_msgcount) 601 continue; 602 fp->f_flag |= FMARK; 603 } 604 if (fp->f_type != DTYPE_SOCKET) 605 continue; 606 so = (struct socket *)fp->f_data; 607 if (so->so_proto->pr_domain != &unixdomain || 608 (so->so_proto->pr_flags&PR_RIGHTS) == 0) 609 continue; 610 if (so->so_rcv.sb_flags & SB_LOCK) { 611 sbwait(&so->so_rcv); 612 goto restart; 613 } 614 unp_scan(so->so_rcv.sb_mb, unp_mark); 615 } 616 } while (unp_defer); 617 for (fp = file; fp < fileNFILE; fp++) { 618 if (fp->f_count == 0) 619 continue; 620 if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0) 621 while (fp->f_msgcount) 622 unp_discard(fp); 623 } 624 unp_gcing = 0; 625 } 626 627 unp_dispose(m) 628 struct mbuf *m; 629 { 630 int unp_discard(); 631 632 if (m) 633 unp_scan(m, unp_discard); 634 } 635 636 unp_scan(m0, op) 637 register struct mbuf *m0; 638 int (*op)(); 639 { 640 register struct mbuf *m; 641 register struct file **rp; 642 register int i; 643 int qfds; 644 645 while (m0) { 646 for (m = m0; m; m = m->m_next) 647 if (m->m_type == MT_RIGHTS && m->m_len) { 648 qfds = m->m_len / sizeof (struct file *); 649 rp = mtod(m, struct file **); 650 for (i = 0; i < qfds; i++) 651 (*op)(*rp++); 652 break; /* XXX, but saves time */ 653 } 654 m0 = m0->m_act; 655 } 656 } 657 658 unp_mark(fp) 659 struct file *fp; 660 { 661 662 if (fp->f_flag & FMARK) 663 return; 664 unp_defer++; 665 fp->f_flag |= (FMARK|FDEFER); 666 } 667 668 unp_discard(fp) 669 struct file *fp; 670 { 671 672 fp->f_msgcount--; 673 unp_rights--; 674 closef(fp); 675 } 676