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