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