1 /* uipc_usrreq.c 1.14 83/06/14 */ 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_SLOWTIMO: 216 break; 217 218 default: 219 panic("piusrreq"); 220 } 221 release: 222 if (m) 223 m_freem(m); 224 return (error); 225 } 226 227 /* SHOULD BE PIPSIZ and 0 */ 228 int unp_sendspace = 1024*2; 229 int unp_recvspace = 1024*2; 230 231 unp_attach(so) 232 struct socket *so; 233 { 234 register struct mbuf *m; 235 register struct unpcb *unp; 236 int error; 237 238 error = soreserve(so, unp_sendspace, unp_recvspace); 239 if (error) 240 return (error); 241 m = m_getclr(M_DONTWAIT, MT_PCB); 242 if (m == NULL) 243 return (ENOBUFS); 244 unp = mtod(m, struct unpcb *); 245 so->so_pcb = (caddr_t)unp; 246 unp->unp_socket = so; 247 return (0); 248 } 249 250 unp_detach(unp) 251 register struct unpcb *unp; 252 { 253 254 if (unp->unp_inode) { 255 irele(unp->unp_inode); 256 unp->unp_inode = 0; 257 } 258 if (unp->unp_conn) 259 unp_disconnect(unp); 260 while (unp->unp_refs) 261 unp_drop(unp->unp_refs, ECONNRESET); 262 soisdisconnected(unp->unp_socket); 263 unp->unp_socket->so_pcb = 0; 264 m_freem(unp->unp_remaddr); 265 (void) m_free(dtom(unp)); 266 } 267 268 unp_bind(unp, nam) 269 struct unpcb *unp; 270 struct mbuf *nam; 271 { 272 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 273 register struct inode *ip; 274 extern schar(); 275 int error; 276 277 u.u_dirp = soun->sun_path; 278 if (nam->m_len == MLEN) 279 return (EINVAL); 280 *(mtod(nam, caddr_t) + nam->m_len) = 0; 281 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 282 ip = namei(schar, CREATE, 1); 283 if (ip) { 284 iput(ip); 285 return (EADDRINUSE); 286 } 287 if (error = u.u_error) { 288 u.u_error = 0; /* XXX */ 289 return (error); 290 } 291 ip = maknode(IFSOCK | 0777); 292 if (ip == NULL) { 293 error = u.u_error; /* XXX */ 294 u.u_error = 0; /* XXX */ 295 return (error); 296 } 297 ip->i_socket = unp->unp_socket; 298 unp->unp_inode = ip; 299 iunlock(ip); /* but keep reference */ 300 return (0); 301 } 302 303 unp_connect(so, nam) 304 struct socket *so; 305 struct mbuf *nam; 306 { 307 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 308 register struct inode *ip; 309 int error; 310 register struct socket *so2; 311 312 u.u_dirp = soun->sun_path; 313 if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 314 return (EMSGSIZE); 315 *(mtod(nam, caddr_t) + nam->m_len) = 0; 316 ip = namei(schar, LOOKUP, 1); 317 if (ip == 0) { 318 error = u.u_error; 319 u.u_error = 0; 320 return (error); /* XXX */ 321 } 322 if ((ip->i_mode&IFMT) != IFSOCK) { 323 error = ENOTSOCK; 324 goto bad; 325 } 326 so2 = ip->i_socket; 327 if (so2 == 0) { 328 error = ECONNREFUSED; 329 goto bad; 330 } 331 if (so->so_type != so2->so_type) { 332 error = EPROTOTYPE; 333 goto bad; 334 } 335 if (so->so_proto->pr_flags & PR_CONNREQUIRED && 336 ((so2->so_options&SO_ACCEPTCONN) == 0 || 337 (so2 = sonewconn(so2)) == 0)) { 338 error = ECONNREFUSED; 339 goto bad; 340 } 341 error = unp_connect2(so, nam, so2); 342 bad: 343 iput(ip); 344 return (error); 345 } 346 347 unp_connect2(so, sonam, so2) 348 register struct socket *so; 349 struct mbuf *sonam; 350 register struct socket *so2; 351 { 352 register struct unpcb *unp = sotounpcb(so); 353 register struct unpcb *unp2; 354 355 if (so2->so_type != so->so_type) 356 return (EPROTOTYPE); 357 switch (so->so_type) { 358 359 case SOCK_DGRAM: 360 unp2 = sotounpcb(so2); 361 unp->unp_conn = unp2; 362 unp->unp_nextref = unp2->unp_refs; 363 unp2->unp_refs = unp; 364 break; 365 366 case SOCK_STREAM: 367 unp2 = sotounpcb(so2); 368 unp->unp_conn = unp2; 369 unp2->unp_conn = unp; 370 if (sonam) 371 unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 372 break; 373 374 default: 375 panic("unp_connect2"); 376 } 377 soisconnected(so2); 378 soisconnected(so); 379 return (0); 380 } 381 382 unp_disconnect(unp) 383 struct unpcb *unp; 384 { 385 register struct unpcb *unp2 = unp->unp_conn; 386 387 if (unp2 == 0) 388 return; 389 unp->unp_conn = 0; 390 soisdisconnected(unp->unp_socket); 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 unp2->unp_conn = 0; 412 soisdisconnected(unp2->unp_socket); 413 break; 414 } 415 } 416 417 #ifdef notdef 418 unp_abort(unp) 419 struct unpcb *unp; 420 { 421 422 unp_detach(unp); 423 } 424 #endif 425 426 /*ARGSUSED*/ 427 unp_usrclosed(unp) 428 struct unpcb *unp; 429 { 430 431 } 432 433 unp_drop(unp, errno) 434 struct unpcb *unp; 435 int errno; 436 { 437 438 unp->unp_socket->so_error = errno; 439 unp_disconnect(unp); 440 } 441 442 #ifdef notdef 443 unp_drain() 444 { 445 446 } 447 #endif 448 449 unp_externalize(rights) 450 struct mbuf *rights; 451 { 452 int newfds = rights->m_len / sizeof (int); 453 register int i; 454 register struct file **rp = mtod(rights, struct file **); 455 register struct file *fp; 456 int f; 457 458 if (newfds > ufavail()) { 459 for (i = 0; i < newfds; i++) { 460 fp = *rp; 461 unp_discard(fp); 462 *rp++ = 0; 463 } 464 return (EMSGSIZE); 465 } 466 for (i = 0; i < newfds; i++) { 467 f = ufalloc(0); 468 if (f < 0) 469 panic("unp_externalize"); 470 fp = *rp; 471 u.u_ofile[f] = fp; 472 fp->f_msgcount--; 473 *(int *)rp = f; 474 } 475 return (0); 476 } 477 478 unp_internalize(rights) 479 struct mbuf *rights; 480 { 481 register struct file **rp; 482 int oldfds = rights->m_len / sizeof (int); 483 register int i; 484 register struct file *fp; 485 486 rp = mtod(rights, struct file **); 487 for (i = 0; i < oldfds; i++) 488 if (getf(*(int *)rp++) == 0) 489 return (EBADF); 490 rp = mtod(rights, struct file **); 491 for (i = 0; i < oldfds; i++) { 492 fp = getf(*(int *)rp); 493 *rp++ = fp; 494 fp->f_count++; 495 fp->f_msgcount++; 496 } 497 return (0); 498 } 499 500 int unp_defer, unp_gcing; 501 int unp_mark(); 502 503 unp_gc() 504 { 505 register struct file *fp; 506 register struct socket *so; 507 508 if (unp_gcing) 509 return; 510 unp_gcing = 1; 511 restart: 512 unp_defer = 0; 513 for (fp = file; fp < fileNFILE; fp++) 514 fp->f_flag &= ~(FMARK|FDEFER); 515 do { 516 for (fp = file; fp < fileNFILE; fp++) { 517 if (fp->f_count == 0) 518 continue; 519 if (fp->f_flag & FDEFER) { 520 fp->f_flag &= ~FDEFER; 521 unp_defer--; 522 } else { 523 if (fp->f_flag & FMARK) 524 continue; 525 if (fp->f_count == fp->f_msgcount) 526 continue; 527 fp->f_flag |= FMARK; 528 } 529 if (fp->f_type != DTYPE_SOCKET) 530 continue; 531 so = (struct socket *)fp->f_data; 532 if (so->so_proto->pr_family != AF_UNIX || 533 (so->so_proto->pr_flags&PR_ADDR) == 0) 534 continue; 535 if (so->so_rcv.sb_flags & SB_LOCK) { 536 sbwait(&so->so_rcv); 537 goto restart; 538 } 539 unp_scan(so->so_rcv.sb_mb, unp_mark); 540 } 541 } while (unp_defer); 542 for (fp = file; fp < fileNFILE; fp++) { 543 if (fp->f_count == 0) 544 continue; 545 if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 546 if (fp->f_type != DTYPE_SOCKET) 547 panic("unp_gc"); 548 (void) soshutdown((struct socket *)fp->f_data, 0); 549 } 550 } 551 unp_gcing = 0; 552 } 553 554 unp_scan(m, op) 555 register struct mbuf *m; 556 int (*op)(); 557 { 558 register struct file **rp; 559 register int i; 560 int qfds; 561 562 while (m) { 563 m = m->m_next; 564 if (m == 0) 565 goto bad; 566 if (m->m_len) { 567 qfds = m->m_len / sizeof (struct file *); 568 rp = mtod(m, struct file **); 569 for (i = 0; i < qfds; i++) 570 (*op)(*rp++); 571 } 572 do { 573 m = m->m_next; 574 if (m == 0) 575 goto bad; 576 } while (m->m_act == 0); 577 m = m->m_next; 578 } 579 return; 580 bad: 581 panic("unp_gcscan"); 582 } 583 584 unp_mark(fp) 585 struct file *fp; 586 { 587 588 if (fp->f_flag & FMARK) 589 return; 590 unp_defer++; 591 fp->f_flag |= (FMARK|FDEFER); 592 } 593 594 unp_discard(fp) 595 struct file *fp; 596 { 597 598 fp->f_msgcount--; 599 closef(fp); 600 } 601