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