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