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