1 /* uipc_usrreq.c 1.15 83/07/21 */ 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 unp2 = sotounpcb(so2); 358 unp->unp_conn = unp2; 359 switch (so->so_type) { 360 361 case SOCK_DGRAM: 362 unp->unp_nextref = unp2->unp_refs; 363 unp2->unp_refs = unp; 364 break; 365 366 case SOCK_STREAM: 367 unp2->unp_conn = unp; 368 if (sonam) 369 unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 370 soisconnected(so2); 371 soisconnected(so); 372 break; 373 374 default: 375 panic("unp_connect2"); 376 } 377 return (0); 378 } 379 380 unp_disconnect(unp) 381 struct unpcb *unp; 382 { 383 register struct unpcb *unp2 = unp->unp_conn; 384 385 if (unp2 == 0) 386 return; 387 unp->unp_conn = 0; 388 switch (unp->unp_socket->so_type) { 389 390 case SOCK_DGRAM: 391 if (unp2->unp_refs == unp) 392 unp2->unp_refs = unp->unp_nextref; 393 else { 394 unp2 = unp2->unp_refs; 395 for (;;) { 396 if (unp2 == 0) 397 panic("unp_disconnect"); 398 if (unp2->unp_nextref == unp) 399 break; 400 unp2 = unp2->unp_nextref; 401 } 402 unp2->unp_nextref = unp->unp_nextref; 403 } 404 unp->unp_nextref = 0; 405 break; 406 407 case SOCK_STREAM: 408 soisdisconnected(unp->unp_socket); 409 unp2->unp_conn = 0; 410 soisdisconnected(unp2->unp_socket); 411 break; 412 } 413 } 414 415 #ifdef notdef 416 unp_abort(unp) 417 struct unpcb *unp; 418 { 419 420 unp_detach(unp); 421 } 422 #endif 423 424 /*ARGSUSED*/ 425 unp_usrclosed(unp) 426 struct unpcb *unp; 427 { 428 429 } 430 431 unp_drop(unp, errno) 432 struct unpcb *unp; 433 int errno; 434 { 435 436 unp->unp_socket->so_error = errno; 437 unp_disconnect(unp); 438 } 439 440 #ifdef notdef 441 unp_drain() 442 { 443 444 } 445 #endif 446 447 unp_externalize(rights) 448 struct mbuf *rights; 449 { 450 int newfds = rights->m_len / sizeof (int); 451 register int i; 452 register struct file **rp = mtod(rights, struct file **); 453 register struct file *fp; 454 int f; 455 456 if (newfds > ufavail()) { 457 for (i = 0; i < newfds; i++) { 458 fp = *rp; 459 unp_discard(fp); 460 *rp++ = 0; 461 } 462 return (EMSGSIZE); 463 } 464 for (i = 0; i < newfds; i++) { 465 f = ufalloc(0); 466 if (f < 0) 467 panic("unp_externalize"); 468 fp = *rp; 469 u.u_ofile[f] = fp; 470 fp->f_msgcount--; 471 *(int *)rp = f; 472 } 473 return (0); 474 } 475 476 unp_internalize(rights) 477 struct mbuf *rights; 478 { 479 register struct file **rp; 480 int oldfds = rights->m_len / sizeof (int); 481 register int i; 482 register struct file *fp; 483 484 rp = mtod(rights, struct file **); 485 for (i = 0; i < oldfds; i++) 486 if (getf(*(int *)rp++) == 0) 487 return (EBADF); 488 rp = mtod(rights, struct file **); 489 for (i = 0; i < oldfds; i++) { 490 fp = getf(*(int *)rp); 491 *rp++ = fp; 492 fp->f_count++; 493 fp->f_msgcount++; 494 } 495 return (0); 496 } 497 498 int unp_defer, unp_gcing; 499 int unp_mark(); 500 501 unp_gc() 502 { 503 register struct file *fp; 504 register struct socket *so; 505 506 if (unp_gcing) 507 return; 508 unp_gcing = 1; 509 restart: 510 unp_defer = 0; 511 for (fp = file; fp < fileNFILE; fp++) 512 fp->f_flag &= ~(FMARK|FDEFER); 513 do { 514 for (fp = file; fp < fileNFILE; fp++) { 515 if (fp->f_count == 0) 516 continue; 517 if (fp->f_flag & FDEFER) { 518 fp->f_flag &= ~FDEFER; 519 unp_defer--; 520 } else { 521 if (fp->f_flag & FMARK) 522 continue; 523 if (fp->f_count == fp->f_msgcount) 524 continue; 525 fp->f_flag |= FMARK; 526 } 527 if (fp->f_type != DTYPE_SOCKET) 528 continue; 529 so = (struct socket *)fp->f_data; 530 if (so->so_proto->pr_family != AF_UNIX || 531 (so->so_proto->pr_flags&PR_ADDR) == 0) 532 continue; 533 if (so->so_rcv.sb_flags & SB_LOCK) { 534 sbwait(&so->so_rcv); 535 goto restart; 536 } 537 unp_scan(so->so_rcv.sb_mb, unp_mark); 538 } 539 } while (unp_defer); 540 for (fp = file; fp < fileNFILE; fp++) { 541 if (fp->f_count == 0) 542 continue; 543 if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 544 if (fp->f_type != DTYPE_SOCKET) 545 panic("unp_gc"); 546 (void) soshutdown((struct socket *)fp->f_data, 0); 547 } 548 } 549 unp_gcing = 0; 550 } 551 552 unp_scan(m, op) 553 register struct mbuf *m; 554 int (*op)(); 555 { 556 register struct file **rp; 557 register int i; 558 int qfds; 559 560 while (m) { 561 m = m->m_next; 562 if (m == 0) 563 goto bad; 564 if (m->m_len) { 565 qfds = m->m_len / sizeof (struct file *); 566 rp = mtod(m, struct file **); 567 for (i = 0; i < qfds; i++) 568 (*op)(*rp++); 569 } 570 do { 571 m = m->m_next; 572 if (m == 0) 573 goto bad; 574 } while (m->m_act == 0); 575 m = m->m_next; 576 } 577 return; 578 bad: 579 panic("unp_gcscan"); 580 } 581 582 unp_mark(fp) 583 struct file *fp; 584 { 585 586 if (fp->f_flag & FMARK) 587 return; 588 unp_defer++; 589 fp->f_flag |= (FMARK|FDEFER); 590 } 591 592 unp_discard(fp) 593 struct file *fp; 594 { 595 596 fp->f_msgcount--; 597 closef(fp); 598 } 599