1 /* uipc_usrreq.c 6.8 84/08/21 */ 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 irele(unp->unp_inode); 282 unp->unp_inode = 0; 283 } 284 if (unp->unp_conn) 285 unp_disconnect(unp); 286 while (unp->unp_refs) 287 unp_drop(unp->unp_refs, ECONNRESET); 288 soisdisconnected(unp->unp_socket); 289 unp->unp_socket->so_pcb = 0; 290 m_freem(unp->unp_remaddr); 291 (void) m_free(dtom(unp)); 292 } 293 294 unp_bind(unp, nam) 295 struct unpcb *unp; 296 struct mbuf *nam; 297 { 298 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 299 register struct inode *ip; 300 register struct nameidata *ndp = &u.u_nd; 301 int error; 302 303 ndp->ni_dirp = soun->sun_path; 304 if (nam->m_len == MLEN) 305 return (EINVAL); 306 *(mtod(nam, caddr_t) + nam->m_len) = 0; 307 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 308 ndp->ni_nameiop = CREATE | FOLLOW; 309 ndp->ni_segflg = UIO_SYSSPACE; 310 ip = namei(ndp); 311 if (ip) { 312 iput(ip); 313 return (EADDRINUSE); 314 } 315 if (error = u.u_error) { 316 u.u_error = 0; /* XXX */ 317 return (error); 318 } 319 ip = maknode(IFSOCK | 0777, ndp); 320 if (ip == NULL) { 321 error = u.u_error; /* XXX */ 322 u.u_error = 0; /* XXX */ 323 return (error); 324 } 325 ip->i_socket = unp->unp_socket; 326 unp->unp_inode = ip; 327 iunlock(ip); /* but keep reference */ 328 return (0); 329 } 330 331 unp_connect(so, nam) 332 struct socket *so; 333 struct mbuf *nam; 334 { 335 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 336 register struct inode *ip; 337 int error; 338 register struct socket *so2; 339 register struct nameidata *ndp = &u.u_nd; 340 341 ndp->ni_dirp = soun->sun_path; 342 if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 343 return (EMSGSIZE); 344 *(mtod(nam, caddr_t) + nam->m_len) = 0; 345 ndp->ni_nameiop = LOOKUP | FOLLOW; 346 ndp->ni_segflg = UIO_SYSSPACE; 347 ip = namei(ndp); 348 if (ip == 0) { 349 error = u.u_error; 350 u.u_error = 0; 351 return (error); /* XXX */ 352 } 353 if ((ip->i_mode&IFMT) != IFSOCK) { 354 error = ENOTSOCK; 355 goto bad; 356 } 357 so2 = ip->i_socket; 358 if (so2 == 0) { 359 error = ECONNREFUSED; 360 goto bad; 361 } 362 if (so->so_type != so2->so_type) { 363 error = EPROTOTYPE; 364 goto bad; 365 } 366 if (so->so_proto->pr_flags & PR_CONNREQUIRED && 367 ((so2->so_options&SO_ACCEPTCONN) == 0 || 368 (so2 = sonewconn(so2)) == 0)) { 369 error = ECONNREFUSED; 370 goto bad; 371 } 372 error = unp_connect2(so, nam, so2); 373 bad: 374 iput(ip); 375 return (error); 376 } 377 378 unp_connect2(so, sonam, so2) 379 register struct socket *so; 380 struct mbuf *sonam; 381 register struct socket *so2; 382 { 383 register struct unpcb *unp = sotounpcb(so); 384 register struct unpcb *unp2; 385 386 if (so2->so_type != so->so_type) 387 return (EPROTOTYPE); 388 unp2 = sotounpcb(so2); 389 unp->unp_conn = unp2; 390 switch (so->so_type) { 391 392 case SOCK_DGRAM: 393 unp->unp_nextref = unp2->unp_refs; 394 unp2->unp_refs = unp; 395 break; 396 397 case SOCK_STREAM: 398 unp2->unp_conn = unp; 399 if (sonam) 400 unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 401 soisconnected(so2); 402 soisconnected(so); 403 break; 404 405 default: 406 panic("unp_connect2"); 407 } 408 return (0); 409 } 410 411 unp_disconnect(unp) 412 struct unpcb *unp; 413 { 414 register struct unpcb *unp2 = unp->unp_conn; 415 416 if (unp2 == 0) 417 return; 418 unp->unp_conn = 0; 419 switch (unp->unp_socket->so_type) { 420 421 case SOCK_DGRAM: 422 if (unp2->unp_refs == unp) 423 unp2->unp_refs = unp->unp_nextref; 424 else { 425 unp2 = unp2->unp_refs; 426 for (;;) { 427 if (unp2 == 0) 428 panic("unp_disconnect"); 429 if (unp2->unp_nextref == unp) 430 break; 431 unp2 = unp2->unp_nextref; 432 } 433 unp2->unp_nextref = unp->unp_nextref; 434 } 435 unp->unp_nextref = 0; 436 break; 437 438 case SOCK_STREAM: 439 soisdisconnected(unp->unp_socket); 440 unp2->unp_conn = 0; 441 soisdisconnected(unp2->unp_socket); 442 break; 443 } 444 } 445 446 #ifdef notdef 447 unp_abort(unp) 448 struct unpcb *unp; 449 { 450 451 unp_detach(unp); 452 } 453 #endif 454 455 /*ARGSUSED*/ 456 unp_usrclosed(unp) 457 struct unpcb *unp; 458 { 459 460 } 461 462 unp_drop(unp, errno) 463 struct unpcb *unp; 464 int errno; 465 { 466 struct socket *so = unp->unp_socket; 467 468 so->so_error = errno; 469 unp_disconnect(unp); 470 if (so->so_head) { 471 so->so_pcb = (caddr_t) 0; 472 m_freem(unp->unp_remaddr); 473 (void) m_free(dtom(unp)); 474 sofree(so); 475 } 476 } 477 478 #ifdef notdef 479 unp_drain() 480 { 481 482 } 483 #endif 484 485 unp_externalize(rights) 486 struct mbuf *rights; 487 { 488 int newfds = rights->m_len / sizeof (int); 489 register int i; 490 register struct file **rp = mtod(rights, struct file **); 491 register struct file *fp; 492 int f; 493 494 if (newfds > ufavail()) { 495 for (i = 0; i < newfds; i++) { 496 fp = *rp; 497 unp_discard(fp); 498 *rp++ = 0; 499 } 500 return (EMSGSIZE); 501 } 502 for (i = 0; i < newfds; i++) { 503 f = ufalloc(0); 504 if (f < 0) 505 panic("unp_externalize"); 506 fp = *rp; 507 u.u_ofile[f] = fp; 508 fp->f_msgcount--; 509 *(int *)rp++ = f; 510 } 511 return (0); 512 } 513 514 unp_internalize(rights) 515 struct mbuf *rights; 516 { 517 register struct file **rp; 518 int oldfds = rights->m_len / sizeof (int); 519 register int i; 520 register struct file *fp; 521 522 rp = mtod(rights, struct file **); 523 for (i = 0; i < oldfds; i++) 524 if (getf(*(int *)rp++) == 0) 525 return (EBADF); 526 rp = mtod(rights, struct file **); 527 for (i = 0; i < oldfds; i++) { 528 fp = getf(*(int *)rp); 529 *rp++ = fp; 530 fp->f_count++; 531 fp->f_msgcount++; 532 } 533 return (0); 534 } 535 536 int unp_defer, unp_gcing; 537 int unp_mark(); 538 extern struct domain unixdomain; 539 540 unp_gc() 541 { 542 register struct file *fp; 543 register struct socket *so; 544 545 if (unp_gcing) 546 return; 547 unp_gcing = 1; 548 restart: 549 unp_defer = 0; 550 for (fp = file; fp < fileNFILE; fp++) 551 fp->f_flag &= ~(FMARK|FDEFER); 552 do { 553 for (fp = file; fp < fileNFILE; fp++) { 554 if (fp->f_count == 0) 555 continue; 556 if (fp->f_flag & FDEFER) { 557 fp->f_flag &= ~FDEFER; 558 unp_defer--; 559 } else { 560 if (fp->f_flag & FMARK) 561 continue; 562 if (fp->f_count == fp->f_msgcount) 563 continue; 564 fp->f_flag |= FMARK; 565 } 566 if (fp->f_type != DTYPE_SOCKET) 567 continue; 568 so = (struct socket *)fp->f_data; 569 if (so->so_proto->pr_domain != &unixdomain || 570 (so->so_proto->pr_flags&PR_ADDR) == 0) 571 continue; 572 if (so->so_rcv.sb_flags & SB_LOCK) { 573 sbwait(&so->so_rcv); 574 goto restart; 575 } 576 unp_scan(so->so_rcv.sb_mb, unp_mark); 577 } 578 } while (unp_defer); 579 for (fp = file; fp < fileNFILE; fp++) { 580 if (fp->f_count == 0) 581 continue; 582 if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 583 if (fp->f_type != DTYPE_SOCKET) 584 panic("unp_gc"); 585 (void) soshutdown((struct socket *)fp->f_data, 0); 586 } 587 } 588 unp_gcing = 0; 589 } 590 591 unp_dispose(m) 592 struct mbuf *m; 593 { 594 int unp_discard(); 595 596 unp_scan(m, unp_discard); 597 } 598 599 unp_scan(m0, op) 600 register struct mbuf *m0; 601 int (*op)(); 602 { 603 register struct mbuf *m; 604 register struct file **rp; 605 register int i; 606 int qfds = 0; 607 608 while (m0) { 609 for (m = m0; m; m = m->m_next) 610 if (m->m_type == MT_RIGHTS && m->m_len) { 611 qfds = m->m_len / sizeof (struct file *); 612 rp = mtod(m, struct file **); 613 for (i = 0; i < qfds; i++) 614 (*op)(*rp++); 615 break; /* XXX, but saves time */ 616 } 617 m0 = m0->m_next; 618 } 619 if (qfds == 0) 620 panic("unp_gcscan"); 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