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