1 /* uipc_usrreq.c 6.3 84/02/15 */ 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 (void) m_free(dtom(unp)); 445 sofree(so); 446 } 447 } 448 449 #ifdef notdef 450 unp_drain() 451 { 452 453 } 454 #endif 455 456 unp_externalize(rights) 457 struct mbuf *rights; 458 { 459 int newfds = rights->m_len / sizeof (int); 460 register int i; 461 register struct file **rp = mtod(rights, struct file **); 462 register struct file *fp; 463 int f; 464 465 if (newfds > ufavail()) { 466 for (i = 0; i < newfds; i++) { 467 fp = *rp; 468 unp_discard(fp); 469 *rp++ = 0; 470 } 471 return (EMSGSIZE); 472 } 473 for (i = 0; i < newfds; i++) { 474 f = ufalloc(0); 475 if (f < 0) 476 panic("unp_externalize"); 477 fp = *rp; 478 u.u_ofile[f] = fp; 479 fp->f_msgcount--; 480 *(int *)rp++ = f; 481 } 482 return (0); 483 } 484 485 unp_internalize(rights) 486 struct mbuf *rights; 487 { 488 register struct file **rp; 489 int oldfds = rights->m_len / sizeof (int); 490 register int i; 491 register struct file *fp; 492 493 rp = mtod(rights, struct file **); 494 for (i = 0; i < oldfds; i++) 495 if (getf(*(int *)rp++) == 0) 496 return (EBADF); 497 rp = mtod(rights, struct file **); 498 for (i = 0; i < oldfds; i++) { 499 fp = getf(*(int *)rp); 500 *rp++ = fp; 501 fp->f_count++; 502 fp->f_msgcount++; 503 } 504 return (0); 505 } 506 507 int unp_defer, unp_gcing; 508 int unp_mark(); 509 510 unp_gc() 511 { 512 register struct file *fp; 513 register struct socket *so; 514 515 if (unp_gcing) 516 return; 517 unp_gcing = 1; 518 restart: 519 unp_defer = 0; 520 for (fp = file; fp < fileNFILE; fp++) 521 fp->f_flag &= ~(FMARK|FDEFER); 522 do { 523 for (fp = file; fp < fileNFILE; fp++) { 524 if (fp->f_count == 0) 525 continue; 526 if (fp->f_flag & FDEFER) { 527 fp->f_flag &= ~FDEFER; 528 unp_defer--; 529 } else { 530 if (fp->f_flag & FMARK) 531 continue; 532 if (fp->f_count == fp->f_msgcount) 533 continue; 534 fp->f_flag |= FMARK; 535 } 536 if (fp->f_type != DTYPE_SOCKET) 537 continue; 538 so = (struct socket *)fp->f_data; 539 if (so->so_proto->pr_family != AF_UNIX || 540 (so->so_proto->pr_flags&PR_ADDR) == 0) 541 continue; 542 if (so->so_rcv.sb_flags & SB_LOCK) { 543 sbwait(&so->so_rcv); 544 goto restart; 545 } 546 unp_scan(so->so_rcv.sb_mb, unp_mark); 547 } 548 } while (unp_defer); 549 for (fp = file; fp < fileNFILE; fp++) { 550 if (fp->f_count == 0) 551 continue; 552 if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 553 if (fp->f_type != DTYPE_SOCKET) 554 panic("unp_gc"); 555 (void) soshutdown((struct socket *)fp->f_data, 0); 556 } 557 } 558 unp_gcing = 0; 559 } 560 561 unp_scan(m, op) 562 register struct mbuf *m; 563 int (*op)(); 564 { 565 register struct file **rp; 566 register int i; 567 int qfds; 568 569 while (m) { 570 m = m->m_next; 571 if (m == 0) 572 goto bad; 573 if (m->m_len) { 574 qfds = m->m_len / sizeof (struct file *); 575 rp = mtod(m, struct file **); 576 for (i = 0; i < qfds; i++) 577 (*op)(*rp++); 578 } 579 do { 580 m = m->m_next; 581 if (m == 0) 582 goto bad; 583 } while (m->m_act == 0); 584 m = m->m_next; 585 } 586 return; 587 bad: 588 panic("unp_gcscan"); 589 } 590 591 unp_mark(fp) 592 struct file *fp; 593 { 594 595 if (fp->f_flag & FMARK) 596 return; 597 unp_defer++; 598 fp->f_flag |= (FMARK|FDEFER); 599 } 600 601 unp_discard(fp) 602 struct file *fp; 603 { 604 605 fp->f_msgcount--; 606 closef(fp); 607 } 608