1 /* uipc_socket.c 4.41 82/06/14 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/dir.h" 6 #include "../h/user.h" 7 #include "../h/proc.h" 8 #include "../h/file.h" 9 #include "../h/inode.h" 10 #include "../h/buf.h" 11 #include "../h/mbuf.h" 12 #include "../h/protosw.h" 13 #include "../h/socket.h" 14 #include "../h/socketvar.h" 15 #include "../h/stat.h" 16 #include "../h/ioctl.h" 17 #include "../net/in.h" 18 #include "../net/in_systm.h" 19 #include "../net/route.h" 20 21 /* 22 * Socket support routines. 23 * 24 * DEAL WITH INTERRUPT NOTIFICATION. 25 */ 26 27 /* 28 * Create a socket. 29 */ 30 socreate(aso, type, asp, asa, options) 31 struct socket **aso; 32 int type; 33 struct sockproto *asp; 34 struct sockaddr *asa; 35 int options; 36 { 37 register struct protosw *prp; 38 register struct socket *so; 39 struct mbuf *m; 40 int pf, proto, error; 41 COUNT(SOCREATE); 42 43 /* 44 * Use process standard protocol/protocol family if none 45 * specified by address argument. 46 */ 47 if (asp == 0) { 48 pf = PF_INET; /* should be u.u_protof */ 49 proto = 0; 50 } else { 51 pf = asp->sp_family; 52 proto = asp->sp_protocol; 53 } 54 55 /* 56 * If protocol specified, look for it, otherwise 57 * for a protocol of the correct type in the right family. 58 */ 59 if (proto) 60 prp = pffindproto(pf, proto); 61 else 62 prp = pffindtype(pf, type); 63 if (prp == 0) 64 return (EPROTONOSUPPORT); 65 66 /* 67 * Get a socket structure. 68 */ 69 m = m_getclr(M_WAIT); 70 if (m == 0) 71 return (ENOBUFS); 72 so = mtod(m, struct socket *); 73 so->so_options = options; 74 so->so_state = 0; 75 if (u.u_uid == 0) 76 so->so_state = SS_PRIV; 77 78 /* 79 * Attach protocol to socket, initializing 80 * and reserving resources. 81 */ 82 so->so_proto = prp; 83 error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 84 if (error) { 85 if (so->so_snd.sb_mbmax || so->so_rcv.sb_mbmax) 86 panic("socreate"); 87 so->so_state |= SS_USERGONE; 88 sofree(so); 89 return (error); 90 } 91 *aso = so; 92 return (0); 93 } 94 95 sofree(so) 96 struct socket *so; 97 { 98 99 COUNT(SOFREE); 100 if (so->so_pcb || (so->so_state & SS_USERGONE) == 0) 101 return; 102 sbrelease(&so->so_snd); 103 sbrelease(&so->so_rcv); 104 (void) m_free(dtom(so)); 105 } 106 107 /* 108 * Close a socket on last file table reference removal. 109 * Initiate disconnect if connected. 110 * Free socket when disconnect complete. 111 * 112 * THIS IS REALLY A UNIX INTERFACE ROUTINE 113 */ 114 soclose(so, exiting) 115 register struct socket *so; 116 int exiting; 117 { 118 int s = splnet(); /* conservative */ 119 120 COUNT(SOCLOSE); 121 if (so->so_pcb == 0) 122 goto discard; 123 if (exiting) 124 so->so_options |= SO_KEEPALIVE; 125 if (so->so_state & SS_ISCONNECTED) { 126 if ((so->so_state & SS_ISDISCONNECTING) == 0) { 127 u.u_error = sodisconnect(so, (struct sockaddr *)0); 128 if (u.u_error) { 129 if (exiting) 130 goto drop; 131 splx(s); 132 return; 133 } 134 } 135 if ((so->so_options & SO_DONTLINGER) == 0) { 136 if ((so->so_state & SS_ISDISCONNECTING) && 137 (so->so_state & SS_NBIO) && 138 exiting == 0) { 139 u.u_error = EINPROGRESS; 140 splx(s); 141 return; 142 } 143 /* should use tsleep here, for at most linger */ 144 while (so->so_state & SS_ISCONNECTED) 145 sleep((caddr_t)&so->so_timeo, PZERO+1); 146 } 147 } 148 drop: 149 if (so->so_pcb) { 150 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 151 if (exiting == 0 && u.u_error) { 152 splx(s); 153 return; 154 } 155 } 156 discard: 157 so->so_state |= SS_USERGONE; 158 sofree(so); 159 splx(s); 160 } 161 162 /*ARGSUSED*/ 163 sostat(so, sb) 164 struct socket *so; 165 struct stat *sb; 166 { 167 168 COUNT(SOSTAT); 169 bzero((caddr_t)sb, sizeof (*sb)); /* XXX */ 170 return (0); /* XXX */ 171 } 172 173 /* 174 * Accept connection on a socket. 175 */ 176 soaccept(so, asa) 177 struct socket *so; 178 struct sockaddr *asa; 179 { 180 int s = splnet(); 181 int error; 182 183 COUNT(SOACCEPT); 184 if ((so->so_options & SO_ACCEPTCONN) == 0) { 185 error = EINVAL; /* XXX */ 186 goto bad; 187 } 188 if ((so->so_state & SS_CONNAWAITING) == 0) { 189 error = ENOTCONN; 190 goto bad; 191 } 192 so->so_state &= ~SS_CONNAWAITING; 193 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 194 bad: 195 splx(s); 196 return (error); 197 } 198 199 /* 200 * Connect socket to a specified address. 201 * If already connected or connecting, then avoid 202 * the protocol entry, to keep its job simpler. 203 */ 204 soconnect(so, asa) 205 struct socket *so; 206 struct sockaddr *asa; 207 { 208 int s = splnet(); 209 int error; 210 211 COUNT(SOCONNECT); 212 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 213 error = EISCONN; 214 goto bad; 215 } 216 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 217 bad: 218 splx(s); 219 return (error); 220 } 221 222 /* 223 * Disconnect from a socket. 224 * Address parameter is from system call for later multicast 225 * protocols. Check to make sure that connected and no disconnect 226 * in progress (for protocol's sake), and then invoke protocol. 227 */ 228 sodisconnect(so, asa) 229 struct socket *so; 230 struct sockaddr *asa; 231 { 232 int s = splnet(); 233 int error; 234 235 COUNT(SODISCONNECT); 236 if ((so->so_state & SS_ISCONNECTED) == 0) { 237 error = ENOTCONN; 238 goto bad; 239 } 240 if (so->so_state & SS_ISDISCONNECTING) { 241 error = EALREADY; 242 goto bad; 243 } 244 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 245 bad: 246 splx(s); 247 return (error); 248 } 249 250 /* 251 * Send on a socket. 252 * If send must go all at once and message is larger than 253 * send buffering, then hard error. 254 * Lock against other senders. 255 * If must go all at once and not enough room now, then 256 * inform user that this would block and do nothing. 257 */ 258 sosend(so, asa) 259 register struct socket *so; 260 struct sockaddr *asa; 261 { 262 struct mbuf *top = 0; 263 register struct mbuf *m, **mp = ⊤ 264 register u_int len; 265 int error = 0, space, s; 266 267 COUNT(SOSEND); 268 if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 269 return (EMSGSIZE); 270 #ifdef notdef 271 /* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */ 272 if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO)) 273 return (EWOULDBLOCK); 274 #endif 275 restart: 276 sblock(&so->so_snd); 277 #define snderr(errno) { error = errno; splx(s); goto release; } 278 279 again: 280 s = splnet(); 281 if (so->so_state & SS_CANTSENDMORE) { 282 psignal(u.u_procp, SIGPIPE); 283 snderr(EPIPE); 284 } 285 if (so->so_error) { 286 error = so->so_error; 287 so->so_error = 0; /* ??? */ 288 splx(s); 289 goto release; 290 } 291 if ((so->so_state & SS_ISCONNECTED) == 0) { 292 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 293 snderr(ENOTCONN); 294 if (asa == 0) 295 snderr(EDESTADDRREQ); 296 } 297 if (top) { 298 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 299 top = 0; 300 if (error) { 301 splx(s); 302 goto release; 303 } 304 mp = ⊤ 305 } 306 if (u.u_count == 0) { 307 splx(s); 308 goto release; 309 } 310 space = sbspace(&so->so_snd); 311 if (space <= 0 || sosendallatonce(so) && space < u.u_count) { 312 if (so->so_state & SS_NBIO) 313 snderr(EWOULDBLOCK); 314 sbunlock(&so->so_snd); 315 sbwait(&so->so_snd); 316 splx(s); 317 goto restart; 318 } 319 splx(s); 320 while (u.u_count && space > 0) { 321 MGET(m, 1); 322 if (m == NULL) { 323 error = ENOBUFS; /* SIGPIPE? */ 324 goto release; 325 } 326 if (u.u_count >= CLBYTES && space >= CLBYTES) { 327 register struct mbuf *p; 328 MCLGET(p, 1); 329 if (p == 0) 330 goto nopages; 331 m->m_off = (int)p - (int)m; 332 len = CLBYTES; 333 } else { 334 nopages: 335 m->m_off = MMINOFF; 336 len = MIN(MLEN, u.u_count); 337 } 338 iomove(mtod(m, caddr_t), len, B_WRITE); 339 m->m_len = len; 340 *mp = m; 341 mp = &m->m_next; 342 space = sbspace(&so->so_snd); 343 } 344 goto again; 345 346 release: 347 sbunlock(&so->so_snd); 348 if (top) 349 m_freem(top); 350 return (error); 351 } 352 353 soreceive(so, asa) 354 register struct socket *so; 355 struct sockaddr *asa; 356 { 357 register struct mbuf *m, *n; 358 u_int len; 359 int eor, s, error = 0, cnt = u.u_count; 360 caddr_t base = u.u_base; 361 362 COUNT(SORECEIVE); 363 restart: 364 sblock(&so->so_rcv); 365 s = splnet(); 366 367 #define rcverr(errno) { error = errno; splx(s); goto release; } 368 if (so->so_rcv.sb_cc == 0) { 369 if (so->so_error) { 370 error = so->so_error; 371 so->so_error = 0; 372 splx(s); 373 goto release; 374 } 375 if (so->so_state & SS_CANTRCVMORE) { 376 splx(s); 377 goto release; 378 } 379 if ((so->so_state & SS_ISCONNECTED) == 0 && 380 (so->so_proto->pr_flags & PR_CONNREQUIRED)) 381 rcverr(ENOTCONN); 382 if (so->so_state & SS_NBIO) 383 rcverr(EWOULDBLOCK); 384 sbunlock(&so->so_rcv); 385 sbwait(&so->so_rcv); 386 splx(s); 387 goto restart; 388 } 389 m = so->so_rcv.sb_mb; 390 if (m == 0) 391 panic("receive"); 392 if (so->so_proto->pr_flags & PR_ADDR) { 393 if (m->m_len != sizeof (struct sockaddr)) 394 panic("soreceive addr"); 395 if (asa) 396 bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 397 so->so_rcv.sb_cc -= m->m_len; 398 so->so_rcv.sb_mbcnt -= MSIZE; 399 m = m_free(m); 400 if (m == 0) 401 panic("receive 2"); 402 so->so_rcv.sb_mb = m; 403 } 404 so->so_state &= ~SS_RCVATMARK; 405 if (so->so_oobmark && cnt > so->so_oobmark) 406 cnt = so->so_oobmark; 407 eor = 0; 408 do { 409 len = MIN(m->m_len, cnt); 410 splx(s); 411 iomove(mtod(m, caddr_t), len, B_READ); 412 cnt -= len; 413 s = splnet(); 414 if (len == m->m_len) { 415 eor = (int)m->m_act; 416 sbfree(&so->so_rcv, m); 417 so->so_rcv.sb_mb = m->m_next; 418 MFREE(m, n); 419 } else { 420 m->m_off += len; 421 m->m_len -= len; 422 so->so_rcv.sb_cc -= len; 423 } 424 } while ((m = so->so_rcv.sb_mb) && cnt && !eor); 425 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 426 do { 427 if (m == 0) 428 panic("receive 3"); 429 sbfree(&so->so_rcv, m); 430 eor = (int)m->m_act; 431 so->so_rcv.sb_mb = m->m_next; 432 MFREE(m, n); 433 m = n; 434 } while (eor == 0); 435 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 436 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 437 if (so->so_oobmark) { 438 so->so_oobmark -= u.u_base - base; 439 if (so->so_oobmark == 0) 440 so->so_state |= SS_RCVATMARK; 441 } 442 release: 443 sbunlock(&so->so_rcv); 444 splx(s); 445 return (error); 446 } 447 448 sohasoutofband(so) 449 struct socket *so; 450 { 451 452 if (so->so_pgrp == 0) 453 return; 454 if (so->so_pgrp > 0) 455 gsignal(so->so_pgrp, SIGURG); 456 else { 457 struct proc *p = pfind(-so->so_pgrp); 458 459 if (p) 460 psignal(p, SIGURG); 461 } 462 } 463 464 /*ARGSUSED*/ 465 soioctl(so, cmd, cmdp) 466 register struct socket *so; 467 int cmd; 468 register caddr_t cmdp; 469 { 470 471 COUNT(SOIOCTL); 472 switch (cmd) { 473 474 case FIONBIO: { 475 int nbio; 476 if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) { 477 u.u_error = EFAULT; 478 return; 479 } 480 if (nbio) 481 so->so_state |= SS_NBIO; 482 else 483 so->so_state &= ~SS_NBIO; 484 return; 485 } 486 487 case FIOASYNC: { 488 int async; 489 if (copyin(cmdp, (caddr_t)&async, sizeof (async))) { 490 u.u_error = EFAULT; 491 return; 492 } 493 if (async) 494 so->so_state |= SS_ASYNC; 495 else 496 so->so_state &= ~SS_ASYNC; 497 return; 498 } 499 500 case SIOCSKEEP: { 501 int keep; 502 if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) { 503 u.u_error = EFAULT; 504 return; 505 } 506 if (keep) 507 so->so_options &= ~SO_KEEPALIVE; 508 else 509 so->so_options |= SO_KEEPALIVE; 510 return; 511 } 512 513 case SIOCGKEEP: { 514 int keep = (so->so_options & SO_KEEPALIVE) != 0; 515 if (copyout((caddr_t)&keep, cmdp, sizeof (keep))) 516 u.u_error = EFAULT; 517 return; 518 } 519 520 case SIOCSLINGER: { 521 int linger; 522 if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) { 523 u.u_error = EFAULT; 524 return; 525 } 526 so->so_linger = linger; 527 if (so->so_linger) 528 so->so_options &= ~SO_DONTLINGER; 529 else 530 so->so_options |= SO_DONTLINGER; 531 return; 532 } 533 534 case SIOCGLINGER: { 535 int linger = so->so_linger; 536 if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) { 537 u.u_error = EFAULT; 538 return; 539 } 540 } 541 case SIOCSPGRP: { 542 int pgrp; 543 if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) { 544 u.u_error = EFAULT; 545 return; 546 } 547 so->so_pgrp = pgrp; 548 return; 549 } 550 551 case SIOCGPGRP: { 552 int pgrp = so->so_pgrp; 553 if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) { 554 u.u_error = EFAULT; 555 return; 556 } 557 } 558 559 case SIOCDONE: { 560 int flags; 561 if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) { 562 u.u_error = EFAULT; 563 return; 564 } 565 flags++; 566 if (flags & FREAD) { 567 int s = splimp(); 568 socantrcvmore(so); 569 sbflush(&so->so_rcv); 570 splx(s); 571 } 572 if (flags & FWRITE) 573 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); 574 return; 575 } 576 577 case SIOCSENDOOB: { 578 char oob; 579 struct mbuf *m; 580 if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) { 581 u.u_error = EFAULT; 582 return; 583 } 584 m = m_get(M_DONTWAIT); 585 if (m == 0) { 586 u.u_error = ENOBUFS; 587 return; 588 } 589 m->m_off = MMINOFF; 590 m->m_len = 1; 591 *mtod(m, caddr_t) = oob; 592 (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); 593 return; 594 } 595 596 case SIOCRCVOOB: { 597 struct mbuf *m = m_get(M_DONTWAIT); 598 if (m == 0) { 599 u.u_error = ENOBUFS; 600 return; 601 } 602 m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; 603 (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); 604 if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) { 605 u.u_error = EFAULT; 606 return; 607 } 608 m_free(m); 609 return; 610 } 611 612 case SIOCATMARK: { 613 int atmark = (so->so_state&SS_RCVATMARK) != 0; 614 if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) { 615 u.u_error = EFAULT; 616 return; 617 } 618 return; 619 } 620 621 /* routing table update calls */ 622 case SIOCADDRT: 623 case SIOCDELRT: 624 case SIOCCHGRT: { 625 struct rtentry route; 626 if (!suser()) 627 return; 628 if (copyin(cmdp, (caddr_t)&route, sizeof (route))) { 629 u.u_error = EFAULT; 630 return; 631 } 632 u.u_error = rtrequest(cmd, &route); 633 return; 634 } 635 636 /* type/protocol specific ioctls */ 637 } 638 u.u_error = EOPNOTSUPP; 639 } 640