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