1 /* uipc_usrreq.c 1.13 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 * change for names in file system 22 * need a proper out-of-band 23 */ 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 (void) sbappendaddr(&so2->so_rcv, 148 mtod(nam, struct sockaddr *), m, 149 rights); 150 sbwakeup(&so2->so_rcv); 151 m = 0; 152 } 153 /* END XXX */ 154 if (nam) 155 unp_disconnect(unp); 156 break; 157 158 case SOCK_STREAM: 159 #define rcv (&so2->so_rcv) 160 #define snd (&so->so_snd) 161 if (rights && rights->m_len) { 162 error = EOPNOTSUPP; 163 break; 164 } 165 if (unp->unp_conn == 0) 166 panic("uipc 3"); 167 so2 = unp->unp_conn->unp_socket; 168 /* 169 * Send to paired receive port, and then 170 * give it enough resources to hold what it already has. 171 * Wake up readers. 172 */ 173 sbappend(rcv, m); 174 snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 175 rcv->sb_mbmax = rcv->sb_mbcnt; 176 snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 177 rcv->sb_hiwat = rcv->sb_cc; 178 sbwakeup(rcv); 179 #undef snd 180 #undef rcv 181 break; 182 183 default: 184 panic("uipc 4"); 185 } 186 m = 0; 187 break; 188 189 case PRU_ABORT: 190 unp_drop(unp, ECONNABORTED); 191 break; 192 193 /* SOME AS YET UNIMPLEMENTED HOOKS */ 194 case PRU_CONTROL: 195 return (EOPNOTSUPP); 196 197 case PRU_SENSE: 198 error = EOPNOTSUPP; 199 break; 200 /* END UNIMPLEMENTED HOOKS */ 201 202 case PRU_RCVOOB: 203 break; 204 205 case PRU_SENDOOB: 206 break; 207 208 case PRU_SOCKADDR: 209 break; 210 211 case PRU_SLOWTIMO: 212 break; 213 214 default: 215 panic("piusrreq"); 216 } 217 release: 218 if (m) 219 m_freem(m); 220 return (error); 221 } 222 223 /* SHOULD BE PIPSIZ and 0 */ 224 int unp_sendspace = 1024*2; 225 int unp_recvspace = 1024*2; 226 227 unp_attach(so) 228 struct socket *so; 229 { 230 register struct mbuf *m; 231 register struct unpcb *unp; 232 int error; 233 234 error = soreserve(so, unp_sendspace, unp_recvspace); 235 if (error) 236 return (error); 237 m = m_getclr(M_DONTWAIT, MT_PCB); 238 if (m == NULL) 239 return (ENOBUFS); 240 unp = mtod(m, struct unpcb *); 241 so->so_pcb = (caddr_t)unp; 242 unp->unp_socket = so; 243 return (0); 244 } 245 246 unp_detach(unp) 247 register struct unpcb *unp; 248 { 249 250 if (unp->unp_inode) { 251 irele(unp->unp_inode); 252 unp->unp_inode = 0; 253 } 254 if (unp->unp_conn) 255 unp_disconnect(unp); 256 while (unp->unp_refs) 257 unp_drop(unp->unp_refs, ECONNRESET); 258 soisdisconnected(unp->unp_socket); 259 unp->unp_socket->so_pcb = 0; 260 m_freem(unp->unp_remaddr); 261 (void) m_free(dtom(unp)); 262 } 263 264 unp_bind(unp, nam) 265 struct unpcb *unp; 266 struct mbuf *nam; 267 { 268 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 269 register struct inode *ip; 270 extern schar(); 271 int error; 272 273 u.u_dirp = soun->sun_path; 274 if (nam->m_len == MLEN) 275 return (EINVAL); 276 *(mtod(nam, caddr_t) + nam->m_len) = 0; 277 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 278 ip = namei(schar, CREATE, 1); 279 if (ip) { 280 iput(ip); 281 return (EADDRINUSE); 282 } 283 if (error = u.u_error) { 284 u.u_error = 0; /* XXX */ 285 return (error); 286 } 287 ip = maknode(IFSOCK | 0777); 288 if (ip == NULL) { 289 error = u.u_error; /* XXX */ 290 u.u_error = 0; /* XXX */ 291 return (error); 292 } 293 ip->i_socket = unp->unp_socket; 294 unp->unp_inode = ip; 295 iunlock(ip); /* but keep reference */ 296 return (0); 297 } 298 299 unp_connect(so, nam) 300 struct socket *so; 301 struct mbuf *nam; 302 { 303 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 304 register struct inode *ip; 305 int error; 306 register struct socket *so2; 307 308 u.u_dirp = soun->sun_path; 309 if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 310 return (EMSGSIZE); 311 *(mtod(nam, caddr_t) + nam->m_len) = 0; 312 ip = namei(schar, LOOKUP, 1); 313 if (ip == 0) { 314 error = u.u_error; 315 u.u_error = 0; 316 return (error); /* XXX */ 317 } 318 if ((ip->i_mode&IFMT) != IFSOCK) { 319 error = ENOTSOCK; 320 goto bad; 321 } 322 so2 = ip->i_socket; 323 if (so2 == 0) { 324 error = ECONNREFUSED; 325 goto bad; 326 } 327 if (so->so_type != so2->so_type) { 328 error = EPROTOTYPE; 329 goto bad; 330 } 331 if (so->so_proto->pr_flags & PR_CONNREQUIRED && 332 ((so2->so_options&SO_ACCEPTCONN) == 0 || 333 (so2 = sonewconn(so2)) == 0)) { 334 error = ECONNREFUSED; 335 goto bad; 336 } 337 error = unp_connect2(so, nam, so2); 338 bad: 339 iput(ip); 340 return (error); 341 } 342 343 unp_connect2(so, sonam, so2) 344 register struct socket *so; 345 struct mbuf *sonam; 346 register struct socket *so2; 347 { 348 register struct unpcb *unp = sotounpcb(so); 349 register struct unpcb *unp2; 350 351 if (so2->so_type != so->so_type) 352 return (EPROTOTYPE); 353 switch (so->so_type) { 354 355 case SOCK_DGRAM: 356 unp2 = sotounpcb(so2); 357 unp->unp_conn = unp2; 358 unp->unp_nextref = unp2->unp_refs; 359 unp2->unp_refs = unp; 360 break; 361 362 case SOCK_STREAM: 363 unp2 = sotounpcb(so2); 364 unp->unp_conn = unp2; 365 unp2->unp_conn = unp; 366 if (sonam) 367 unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 368 break; 369 370 default: 371 panic("unp_connect2"); 372 } 373 soisconnected(so2); 374 soisconnected(so); 375 return (0); 376 } 377 378 unp_disconnect(unp) 379 struct unpcb *unp; 380 { 381 register struct unpcb *unp2 = unp->unp_conn; 382 383 if (unp2 == 0) 384 return; 385 unp->unp_conn = 0; 386 soisdisconnected(unp->unp_socket); 387 switch (unp->unp_socket->so_type) { 388 389 case SOCK_DGRAM: 390 if (unp2->unp_refs == unp) 391 unp2->unp_refs = unp->unp_nextref; 392 else { 393 unp2 = unp2->unp_refs; 394 for (;;) { 395 if (unp2 == 0) 396 panic("unp_disconnect"); 397 if (unp2->unp_nextref == unp) 398 break; 399 unp2 = unp2->unp_nextref; 400 } 401 unp2->unp_nextref = unp->unp_nextref; 402 } 403 unp->unp_nextref = 0; 404 break; 405 406 case SOCK_STREAM: 407 unp2->unp_conn = 0; 408 soisdisconnected(unp2->unp_socket); 409 break; 410 } 411 } 412 413 #ifdef notdef 414 unp_abort(unp) 415 struct unpcb *unp; 416 { 417 418 unp_detach(unp); 419 } 420 #endif 421 422 /*ARGSUSED*/ 423 unp_usrclosed(unp) 424 struct unpcb *unp; 425 { 426 427 } 428 429 unp_drop(unp, errno) 430 struct unpcb *unp; 431 int errno; 432 { 433 434 unp->unp_socket->so_error = errno; 435 unp_disconnect(unp); 436 } 437 438 #ifdef notdef 439 unp_drain() 440 { 441 442 } 443 #endif 444 445 unp_externalize(rights) 446 struct mbuf *rights; 447 { 448 int newfds = rights->m_len / sizeof (int); 449 register int i; 450 register struct file **rp = mtod(rights, struct file **); 451 register struct file *fp; 452 int f; 453 454 if (newfds > ufavail()) { 455 for (i = 0; i < newfds; i++) { 456 fp = *rp; 457 unp_discard(fp); 458 *rp++ = 0; 459 } 460 return (EMSGSIZE); 461 } 462 for (i = 0; i < newfds; i++) { 463 f = ufalloc(0); 464 if (f < 0) 465 panic("unp_externalize"); 466 fp = *rp; 467 u.u_ofile[f] = fp; 468 fp->f_msgcount--; 469 *(int *)rp = f; 470 } 471 return (0); 472 } 473 474 unp_internalize(rights) 475 struct mbuf *rights; 476 { 477 register struct file **rp; 478 int oldfds = rights->m_len / sizeof (int); 479 register int i; 480 register struct file *fp; 481 482 rp = mtod(rights, struct file **); 483 for (i = 0; i < oldfds; i++) 484 if (getf(*(int *)rp++) == 0) 485 return (EBADF); 486 rp = mtod(rights, struct file **); 487 for (i = 0; i < oldfds; i++) { 488 fp = getf(*(int *)rp); 489 *rp++ = fp; 490 fp->f_count++; 491 fp->f_msgcount++; 492 } 493 return (0); 494 } 495 496 int unp_defer, unp_gcing; 497 int unp_mark(); 498 499 unp_gc() 500 { 501 register struct file *fp; 502 register struct socket *so; 503 504 if (unp_gcing) 505 return; 506 unp_gcing = 1; 507 restart: 508 unp_defer = 0; 509 for (fp = file; fp < fileNFILE; fp++) 510 fp->f_flag &= ~(FMARK|FDEFER); 511 do { 512 for (fp = file; fp < fileNFILE; fp++) { 513 if (fp->f_count == 0) 514 continue; 515 if (fp->f_flag & FDEFER) { 516 fp->f_flag &= ~FDEFER; 517 unp_defer--; 518 } else { 519 if (fp->f_flag & FMARK) 520 continue; 521 if (fp->f_count == fp->f_msgcount) 522 continue; 523 fp->f_flag |= FMARK; 524 } 525 if (fp->f_type != DTYPE_SOCKET) 526 continue; 527 so = (struct socket *)fp->f_data; 528 if (so->so_proto->pr_family != AF_UNIX || 529 (so->so_proto->pr_flags&PR_ADDR) == 0) 530 continue; 531 if (so->so_rcv.sb_flags & SB_LOCK) { 532 sbwait(&so->so_rcv); 533 goto restart; 534 } 535 unp_scan(so->so_rcv.sb_mb, unp_mark); 536 } 537 } while (unp_defer); 538 for (fp = file; fp < fileNFILE; fp++) { 539 if (fp->f_count == 0) 540 continue; 541 if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 542 if (fp->f_type != DTYPE_SOCKET) 543 panic("unp_gc"); 544 (void) soshutdown((struct socket *)fp->f_data, 0); 545 } 546 } 547 unp_gcing = 0; 548 } 549 550 unp_scan(m, op) 551 register struct mbuf *m; 552 int (*op)(); 553 { 554 register struct file **rp; 555 register int i; 556 int qfds; 557 558 while (m) { 559 m = m->m_next; 560 if (m == 0) 561 goto bad; 562 if (m->m_len) { 563 qfds = m->m_len / sizeof (struct file *); 564 rp = mtod(m, struct file **); 565 for (i = 0; i < qfds; i++) 566 (*op)(*rp++); 567 } 568 do { 569 m = m->m_next; 570 if (m == 0) 571 goto bad; 572 } while (m->m_act == 0); 573 m = m->m_next; 574 } 575 return; 576 bad: 577 panic("unp_gcscan"); 578 } 579 580 unp_mark(fp) 581 struct file *fp; 582 { 583 584 if (fp->f_flag & FMARK) 585 return; 586 unp_defer++; 587 fp->f_flag |= (FMARK|FDEFER); 588 } 589 590 unp_discard(fp) 591 struct file *fp; 592 { 593 594 fp->f_msgcount--; 595 closef(fp); 596 } 597