1 /* uipc_socket.c 4.43 82/07/22 */ 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 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 if (so->so_snd.sb_mbmax || so->so_rcv.sb_mbmax) 85 panic("socreate"); 86 so->so_state |= SS_USERGONE; 87 sofree(so); 88 return (error); 89 } 90 *aso = so; 91 return (0); 92 } 93 94 sofree(so) 95 struct socket *so; 96 { 97 98 if (so->so_pcb || (so->so_state & SS_USERGONE) == 0) 99 return; 100 sbrelease(&so->so_snd); 101 sbrelease(&so->so_rcv); 102 (void) m_free(dtom(so)); 103 } 104 105 /* 106 * Close a socket on last file table reference removal. 107 * Initiate disconnect if connected. 108 * Free socket when disconnect complete. 109 * 110 * THIS IS REALLY A UNIX INTERFACE ROUTINE 111 */ 112 soclose(so, exiting) 113 register struct socket *so; 114 int exiting; 115 { 116 int s = splnet(); /* conservative */ 117 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 bzero((caddr_t)sb, sizeof (*sb)); /* XXX */ 166 return (0); /* XXX */ 167 } 168 169 /* 170 * Accept connection on a socket. 171 */ 172 soaccept(so, asa) 173 struct socket *so; 174 struct sockaddr *asa; 175 { 176 int s = splnet(); 177 int error; 178 179 if ((so->so_options & SO_ACCEPTCONN) == 0) { 180 error = EINVAL; /* XXX */ 181 goto bad; 182 } 183 if ((so->so_state & SS_CONNAWAITING) == 0) { 184 error = ENOTCONN; 185 goto bad; 186 } 187 so->so_state &= ~SS_CONNAWAITING; 188 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 189 bad: 190 splx(s); 191 return (error); 192 } 193 194 /* 195 * Connect socket to a specified address. 196 * If already connected or connecting, then avoid 197 * the protocol entry, to keep its job simpler. 198 */ 199 soconnect(so, asa) 200 struct socket *so; 201 struct sockaddr *asa; 202 { 203 int s = splnet(); 204 int error; 205 206 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 207 error = EISCONN; 208 goto bad; 209 } 210 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 211 bad: 212 splx(s); 213 return (error); 214 } 215 216 /* 217 * Disconnect from a socket. 218 * Address parameter is from system call for later multicast 219 * protocols. Check to make sure that connected and no disconnect 220 * in progress (for protocol's sake), and then invoke protocol. 221 */ 222 sodisconnect(so, asa) 223 struct socket *so; 224 struct sockaddr *asa; 225 { 226 int s = splnet(); 227 int error; 228 229 if ((so->so_state & SS_ISCONNECTED) == 0) { 230 error = ENOTCONN; 231 goto bad; 232 } 233 if (so->so_state & SS_ISDISCONNECTING) { 234 error = EALREADY; 235 goto bad; 236 } 237 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 238 bad: 239 splx(s); 240 return (error); 241 } 242 243 /* 244 * Send on a socket. 245 * If send must go all at once and message is larger than 246 * send buffering, then hard error. 247 * Lock against other senders. 248 * If must go all at once and not enough room now, then 249 * inform user that this would block and do nothing. 250 */ 251 sosend(so, asa) 252 register struct socket *so; 253 struct sockaddr *asa; 254 { 255 struct mbuf *top = 0; 256 register struct mbuf *m, **mp = ⊤ 257 register u_int len; 258 int error = 0, space, s; 259 260 if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 261 return (EMSGSIZE); 262 #ifdef notdef 263 /* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */ 264 if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO)) 265 return (EWOULDBLOCK); 266 #endif 267 restart: 268 sblock(&so->so_snd); 269 #define snderr(errno) { error = errno; splx(s); goto release; } 270 271 again: 272 s = splnet(); 273 if (so->so_state & SS_CANTSENDMORE) { 274 psignal(u.u_procp, SIGPIPE); 275 snderr(EPIPE); 276 } 277 if (so->so_error) { 278 error = so->so_error; 279 so->so_error = 0; /* ??? */ 280 splx(s); 281 goto release; 282 } 283 if ((so->so_state & SS_ISCONNECTED) == 0) { 284 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 285 snderr(ENOTCONN); 286 if (asa == 0) 287 snderr(EDESTADDRREQ); 288 } 289 if (top) { 290 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 291 top = 0; 292 if (error) { 293 splx(s); 294 goto release; 295 } 296 mp = ⊤ 297 } 298 if (u.u_count == 0) { 299 splx(s); 300 goto release; 301 } 302 space = sbspace(&so->so_snd); 303 if (space <= 0 || sosendallatonce(so) && space < u.u_count) { 304 if (so->so_state & SS_NBIO) 305 snderr(EWOULDBLOCK); 306 sbunlock(&so->so_snd); 307 sbwait(&so->so_snd); 308 splx(s); 309 goto restart; 310 } 311 splx(s); 312 while (u.u_count && space > 0) { 313 MGET(m, 1); 314 if (m == NULL) { 315 error = ENOBUFS; /* SIGPIPE? */ 316 goto release; 317 } 318 if (u.u_count >= CLBYTES && space >= CLBYTES) { 319 register struct mbuf *p; 320 MCLGET(p, 1); 321 if (p == 0) 322 goto nopages; 323 m->m_off = (int)p - (int)m; 324 len = CLBYTES; 325 } else { 326 nopages: 327 m->m_off = MMINOFF; 328 len = MIN(MLEN, u.u_count); 329 } 330 iomove(mtod(m, caddr_t), len, B_WRITE); 331 m->m_len = len; 332 *mp = m; 333 mp = &m->m_next; 334 space = sbspace(&so->so_snd); 335 } 336 goto again; 337 338 release: 339 sbunlock(&so->so_snd); 340 if (top) 341 m_freem(top); 342 return (error); 343 } 344 345 soreceive(so, asa) 346 register struct socket *so; 347 struct sockaddr *asa; 348 { 349 register struct mbuf *m, *n; 350 u_int len; 351 int eor, s, error = 0, cnt = u.u_count; 352 caddr_t base = u.u_base; 353 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 switch (cmd) { 463 464 case FIONBIO: { 465 int nbio; 466 if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) { 467 u.u_error = EFAULT; 468 return; 469 } 470 if (nbio) 471 so->so_state |= SS_NBIO; 472 else 473 so->so_state &= ~SS_NBIO; 474 return; 475 } 476 477 case FIOASYNC: { 478 int async; 479 if (copyin(cmdp, (caddr_t)&async, sizeof (async))) { 480 u.u_error = EFAULT; 481 return; 482 } 483 if (async) 484 so->so_state |= SS_ASYNC; 485 else 486 so->so_state &= ~SS_ASYNC; 487 return; 488 } 489 490 case SIOCSKEEP: { 491 int keep; 492 if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) { 493 u.u_error = EFAULT; 494 return; 495 } 496 if (keep) 497 so->so_options |= SO_KEEPALIVE; 498 else 499 so->so_options &= ~SO_KEEPALIVE; 500 return; 501 } 502 503 case SIOCGKEEP: { 504 int keep = (so->so_options & SO_KEEPALIVE) != 0; 505 if (copyout((caddr_t)&keep, cmdp, sizeof (keep))) 506 u.u_error = EFAULT; 507 return; 508 } 509 510 case SIOCSLINGER: { 511 int linger; 512 if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) { 513 u.u_error = EFAULT; 514 return; 515 } 516 so->so_linger = linger; 517 if (so->so_linger) 518 so->so_options &= ~SO_DONTLINGER; 519 else 520 so->so_options |= SO_DONTLINGER; 521 return; 522 } 523 524 case SIOCGLINGER: { 525 int linger = so->so_linger; 526 if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) { 527 u.u_error = EFAULT; 528 return; 529 } 530 } 531 case SIOCSPGRP: { 532 int pgrp; 533 if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) { 534 u.u_error = EFAULT; 535 return; 536 } 537 so->so_pgrp = pgrp; 538 return; 539 } 540 541 case SIOCGPGRP: { 542 int pgrp = so->so_pgrp; 543 if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) { 544 u.u_error = EFAULT; 545 return; 546 } 547 } 548 549 case SIOCDONE: { 550 int flags; 551 if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) { 552 u.u_error = EFAULT; 553 return; 554 } 555 flags++; 556 if (flags & FREAD) { 557 int s = splimp(); 558 socantrcvmore(so); 559 sbflush(&so->so_rcv); 560 splx(s); 561 } 562 if (flags & FWRITE) 563 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); 564 return; 565 } 566 567 case SIOCSENDOOB: { 568 char oob; 569 struct mbuf *m; 570 if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) { 571 u.u_error = EFAULT; 572 return; 573 } 574 m = m_get(M_DONTWAIT); 575 if (m == 0) { 576 u.u_error = ENOBUFS; 577 return; 578 } 579 m->m_off = MMINOFF; 580 m->m_len = 1; 581 *mtod(m, caddr_t) = oob; 582 (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); 583 return; 584 } 585 586 case SIOCRCVOOB: { 587 struct mbuf *m = m_get(M_DONTWAIT); 588 if (m == 0) { 589 u.u_error = ENOBUFS; 590 return; 591 } 592 m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; 593 (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); 594 if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) { 595 u.u_error = EFAULT; 596 return; 597 } 598 m_free(m); 599 return; 600 } 601 602 case SIOCATMARK: { 603 int atmark = (so->so_state&SS_RCVATMARK) != 0; 604 if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) { 605 u.u_error = EFAULT; 606 return; 607 } 608 return; 609 } 610 611 /* routing table update calls */ 612 case SIOCADDRT: 613 case SIOCDELRT: 614 case SIOCCHGRT: { 615 struct rtentry route; 616 if (!suser()) 617 return; 618 if (copyin(cmdp, (caddr_t)&route, sizeof (route))) { 619 u.u_error = EFAULT; 620 return; 621 } 622 u.u_error = rtrequest(cmd, &route); 623 return; 624 } 625 626 /* type/protocol specific ioctls */ 627 } 628 u.u_error = EOPNOTSUPP; 629 } 630