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