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