|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1988, 1993, 1995 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)tcp_usrreq.c 8.5 (Berkeley) 6/21/95 ! 59: */ ! 60: ! 61: #include <sys/param.h> ! 62: #include <sys/systm.h> ! 63: #include <sys/kernel.h> ! 64: #include <sys/malloc.h> ! 65: #include <sys/mbuf.h> ! 66: #include <sys/socket.h> ! 67: #include <sys/socketvar.h> ! 68: #include <sys/protosw.h> ! 69: #include <sys/errno.h> ! 70: #include <sys/stat.h> ! 71: ! 72: #include <net/if.h> ! 73: #include <net/route.h> ! 74: ! 75: #include <netinet/in.h> ! 76: #include <netinet/in_systm.h> ! 77: #include <netinet/ip.h> ! 78: #include <netinet/in_pcb.h> ! 79: #include <netinet/ip_var.h> ! 80: #include <netinet/tcp.h> ! 81: #include <netinet/tcp_fsm.h> ! 82: #include <netinet/tcp_seq.h> ! 83: #include <netinet/tcp_timer.h> ! 84: #include <netinet/tcp_var.h> ! 85: #include <netinet/tcpip.h> ! 86: #include <netinet/tcp_debug.h> ! 87: ! 88: ! 89: ! 90: struct inpcb *tcp_hash_array[N_TCP_HASH_ELEMENTS]; ! 91: struct inpcb *tcp_lport_hash_array[N_TCP_LPORT_HASH_ELEMENTS]; ! 92: struct inpcb_hash_str tcp_hash_str = {tcp_hash_array, ! 93: TCP_HASH_MASK, ! 94: N_TCP_HASH_ELEMENTS}; ! 95: ! 96: struct inpcb_hash_str tcp_lport_hash_str = {tcp_lport_hash_array, ! 97: TCP_LPORT_HASH_MASK, ! 98: N_TCP_LPORT_HASH_ELEMENTS}; ! 99: ! 100: ! 101: /* ! 102: * TCP protocol interface to socket abstraction. ! 103: */ ! 104: extern char *tcpstates[]; ! 105: ! 106: #if DELACK_BITMASK_ON ! 107: extern u_long current_active_connections; ! 108: #endif ! 109: ! 110: ! 111: /* ! 112: * Process a TCP user request for TCP tb. If this is a send request ! 113: * then m is the mbuf chain of send data. If this is a timer expiration ! 114: * (called from the software clock routine), then timertype tells which timer. ! 115: */ ! 116: /*ARGSUSED*/ ! 117: int ! 118: tcp_usrreq(so, req, m, nam, control) ! 119: struct socket *so; ! 120: int req; ! 121: struct mbuf *m, *nam, *control; ! 122: { ! 123: register struct inpcb *inp; ! 124: register struct tcpcb *tp; ! 125: int s; ! 126: int error = 0; ! 127: int ostate; ! 128: ! 129: ! 130: if (req == PRU_CONTROL) ! 131: return (in_control(so, (u_long)m, (caddr_t)nam, ! 132: (struct ifnet *)control)); ! 133: if (control && control->m_len) { ! 134: m_freem(control); ! 135: if (m) ! 136: m_freem(m); ! 137: return (EINVAL); ! 138: } ! 139: ! 140: s = splnet(); ! 141: inp = sotoinpcb(so); ! 142: /* ! 143: * When a TCP is attached to a socket, then there will be ! 144: * a (struct inpcb) pointed at by the socket, and this ! 145: * structure will point at a subsidary (struct tcpcb). ! 146: */ ! 147: if (inp == 0 && req != PRU_ATTACH) { ! 148: splx(s); ! 149: #if 0 ! 150: /* ! 151: * The following corrects an mbuf leak under rare ! 152: * circumstances, but has not been fully tested. ! 153: */ ! 154: if (m && req != PRU_SENSE) ! 155: m_freem(m); ! 156: #else ! 157: /* safer version of fix for mbuf leak */ ! 158: if (m && (req == PRU_SEND || req == PRU_SENDOOB)) ! 159: m_freem(m); ! 160: #endif ! 161: return (EINVAL); /* XXX */ ! 162: } ! 163: if (inp) { ! 164: tp = intotcpcb(inp); ! 165: /* WHAT IF TP IS 0? */ ! 166: #if KPROF ! 167: tcp_acounts[tp->t_state][req]++; ! 168: #endif ! 169: ostate = tp->t_state; ! 170: } else ! 171: ostate = 0; ! 172: switch (req) { ! 173: ! 174: /* ! 175: * TCP attaches to socket via PRU_ATTACH, reserving space, ! 176: * and an internet control block. ! 177: */ ! 178: case PRU_ATTACH: ! 179: if (inp) { ! 180: error = EISCONN; ! 181: break; ! 182: } ! 183: error = tcp_attach(so); ! 184: if (error) ! 185: break; ! 186: if ((so->so_options & SO_LINGER) && so->so_linger == 0) ! 187: so->so_linger = TCP_LINGERTIME; ! 188: tp = sototcpcb(so); ! 189: break; ! 190: ! 191: /* ! 192: * PRU_DETACH detaches the TCP protocol from the socket. ! 193: * If the protocol state is non-embryonic, then can't ! 194: * do this directly: have to initiate a PRU_DISCONNECT, ! 195: * which may finish later; embryonic TCB's can just ! 196: * be discarded here. ! 197: */ ! 198: case PRU_DETACH: ! 199: #if TEMPDEBUG ! 200: printf("PRU_DETACH called for socket %d\n", so); ! 201: #endif ! 202: if (tp->t_state > TCPS_LISTEN) ! 203: tp = tcp_disconnect(tp); ! 204: else ! 205: tp = tcp_close(tp); ! 206: break; ! 207: ! 208: /* ! 209: * Give the socket an address. ! 210: */ ! 211: case PRU_BIND: ! 212: error = in_pcbbind(inp, nam); ! 213: break; ! 214: ! 215: /* ! 216: * Prepare to accept connections. ! 217: */ ! 218: case PRU_LISTEN: ! 219: if (inp->inp_lport == 0) ! 220: error = in_pcbbind(inp, (struct mbuf *)0); ! 221: ! 222: if (error == 0) { ! 223: tp->t_state = TCPS_LISTEN; ! 224: hash_insert(inp); ! 225: } ! 226: break; ! 227: ! 228: /* ! 229: * Initiate connection to peer. ! 230: * Create a template for use in transmissions on this connection. ! 231: * Enter SYN_SENT state, and mark socket as connecting. ! 232: * Start keep-alive timer, and seed output sequence space. ! 233: * Send initial segment on connection. ! 234: */ ! 235: case PRU_CONNECT: ! 236: if (inp->inp_lport == 0) { ! 237: error = in_pcbbind(inp, (struct mbuf *)0); ! 238: if (error) ! 239: break; ! 240: } ! 241: error = in_pcbconnect(inp, nam); ! 242: if (error) ! 243: break; ! 244: ! 245: tp->t_template = tcp_template(tp); ! 246: if (tp->t_template == 0) { ! 247: in_pcbdisconnect(inp); ! 248: error = ENOBUFS; ! 249: break; ! 250: } ! 251: /* Compute window scaling to request. */ ! 252: while (tp->request_r_scale < TCP_MAX_WINSHIFT && ! 253: (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) ! 254: tp->request_r_scale++; ! 255: soisconnecting(so); ! 256: tcpstat.tcps_connattempt++; ! 257: tp->t_state = TCPS_SYN_SENT; ! 258: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; ! 259: tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/4; ! 260: tcp_sendseqinit(tp); ! 261: error = tcp_output(tp); ! 262: break; ! 263: ! 264: /* ! 265: * Create a TCP connection between two sockets. ! 266: */ ! 267: case PRU_CONNECT2: ! 268: error = EOPNOTSUPP; ! 269: break; ! 270: ! 271: /* ! 272: * Initiate disconnect from peer. ! 273: * If connection never passed embryonic stage, just drop; ! 274: * else if don't need to let data drain, then can just drop anyways, ! 275: * else have to begin TCP shutdown process: mark socket disconnecting, ! 276: * drain unread data, state switch to reflect user close, and ! 277: * send segment (e.g. FIN) to peer. Socket will be really disconnected ! 278: * when peer sends FIN and acks ours. ! 279: * ! 280: * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. ! 281: */ ! 282: case PRU_DISCONNECT: ! 283: tp = tcp_disconnect(tp); ! 284: break; ! 285: ! 286: /* ! 287: * Accept a connection. Essentially all the work is ! 288: * done at higher levels; just return the address ! 289: * of the peer, storing through addr. ! 290: */ ! 291: case PRU_ACCEPT: ! 292: in_setpeeraddr(inp, nam); ! 293: break; ! 294: ! 295: /* ! 296: * Mark the connection as being incapable of further output. ! 297: */ ! 298: case PRU_SHUTDOWN: ! 299: socantsendmore(so); ! 300: tp = tcp_usrclosed(tp); ! 301: if (tp) ! 302: error = tcp_output(tp); ! 303: break; ! 304: ! 305: /* ! 306: * After a receive, possibly send window update to peer. ! 307: */ ! 308: case PRU_RCVD: ! 309: (void) tcp_output(tp); ! 310: break; ! 311: ! 312: /* ! 313: * Do a send by putting data in output queue and updating urgent ! 314: * marker if URG set. Possibly send more data. ! 315: */ ! 316: case PRU_SEND: ! 317: sbappend(&so->so_snd, m); ! 318: error = tcp_output(tp); ! 319: break; ! 320: ! 321: /* ! 322: * Abort the TCP. ! 323: */ ! 324: case PRU_ABORT: ! 325: tp = tcp_drop(tp, ECONNABORTED); ! 326: break; ! 327: ! 328: case PRU_SENSE: ! 329: ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; ! 330: (void) splx(s); ! 331: return (0); ! 332: ! 333: case PRU_RCVOOB: ! 334: if ((so->so_oobmark == 0 && ! 335: (so->so_state & SS_RCVATMARK) == 0) || ! 336: so->so_options & SO_OOBINLINE || ! 337: tp->t_oobflags & TCPOOB_HADDATA) { ! 338: error = EINVAL; ! 339: break; ! 340: } ! 341: if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { ! 342: error = EWOULDBLOCK; ! 343: break; ! 344: } ! 345: m->m_len = 1; ! 346: *mtod(m, caddr_t) = tp->t_iobc; ! 347: if (((int)nam & MSG_PEEK) == 0) ! 348: tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA); ! 349: break; ! 350: ! 351: case PRU_SENDOOB: ! 352: if (sbspace(&so->so_snd) < -512) { ! 353: m_freem(m); ! 354: error = ENOBUFS; ! 355: break; ! 356: } ! 357: /* ! 358: * According to RFC961 (Assigned Protocols), ! 359: * the urgent pointer points to the last octet ! 360: * of urgent data. We continue, however, ! 361: * to consider it to indicate the first octet ! 362: * of data past the urgent section. ! 363: * Otherwise, snd_up should be one lower. ! 364: */ ! 365: sbappend(&so->so_snd, m); ! 366: tp->snd_up = tp->snd_una + so->so_snd.sb_cc; ! 367: tp->t_force = 1; ! 368: error = tcp_output(tp); ! 369: tp->t_force = 0; ! 370: break; ! 371: ! 372: case PRU_SOCKADDR: ! 373: in_setsockaddr(inp, nam); ! 374: break; ! 375: ! 376: case PRU_PEERADDR: ! 377: in_setpeeraddr(inp, nam); ! 378: break; ! 379: ! 380: /* ! 381: * TCP slow timer went off; going through this ! 382: * routine for tracing's sake. ! 383: */ ! 384: case PRU_SLOWTIMO: ! 385: tp = tcp_timers(tp, (int)nam); ! 386: req |= (int)nam << 8; /* for debug's sake */ ! 387: break; ! 388: ! 389: default: ! 390: panic("tcp_usrreq"); ! 391: } ! 392: if (tp && (so->so_options & SO_DEBUG)) ! 393: tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); ! 394: splx(s); ! 395: return (error); ! 396: } ! 397: ! 398: int ! 399: tcp_ctloutput(op, so, level, optname, mp) ! 400: int op; ! 401: struct socket *so; ! 402: int level, optname; ! 403: struct mbuf **mp; ! 404: { ! 405: int error = 0, s; ! 406: struct inpcb *inp; ! 407: register struct tcpcb *tp; ! 408: register struct mbuf *m; ! 409: register int i; ! 410: ! 411: s = splnet(); ! 412: inp = sotoinpcb(so); ! 413: if (inp == NULL) { ! 414: splx(s); ! 415: if (op == PRCO_SETOPT && *mp) ! 416: (void) m_free(*mp); ! 417: return (ECONNRESET); ! 418: } ! 419: if (level != IPPROTO_TCP) { ! 420: error = ip_ctloutput(op, so, level, optname, mp); ! 421: splx(s); ! 422: return (error); ! 423: } ! 424: tp = intotcpcb(inp); ! 425: ! 426: switch (op) { ! 427: ! 428: case PRCO_SETOPT: ! 429: m = *mp; ! 430: switch (optname) { ! 431: ! 432: case TCP_NODELAY: ! 433: if (m == NULL || m->m_len < sizeof (int)) ! 434: error = EINVAL; ! 435: else if (*mtod(m, int *)) ! 436: tp->t_flags |= TF_NODELAY; ! 437: else ! 438: tp->t_flags &= ~TF_NODELAY; ! 439: break; ! 440: ! 441: case TCP_MAXSEG: ! 442: if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg) ! 443: tp->t_maxseg = i; ! 444: else ! 445: error = EINVAL; ! 446: break; ! 447: ! 448: default: ! 449: error = ENOPROTOOPT; ! 450: break; ! 451: } ! 452: if (m) ! 453: (void) m_free(m); ! 454: break; ! 455: ! 456: case PRCO_GETOPT: ! 457: *mp = m = m_get(M_WAIT, MT_SOOPTS); ! 458: m->m_len = sizeof(int); ! 459: ! 460: switch (optname) { ! 461: case TCP_NODELAY: ! 462: *mtod(m, int *) = tp->t_flags & TF_NODELAY; ! 463: break; ! 464: case TCP_MAXSEG: ! 465: *mtod(m, int *) = tp->t_maxseg; ! 466: break; ! 467: default: ! 468: error = ENOPROTOOPT; ! 469: break; ! 470: } ! 471: break; ! 472: } ! 473: splx(s); ! 474: return (error); ! 475: } ! 476: ! 477: u_long tcp_sendspace = 1024*8; ! 478: u_long tcp_recvspace = 1024*8; ! 479: ! 480: /* ! 481: * Attach TCP protocol to socket, allocating ! 482: * internet protocol control block, tcp control block, ! 483: * bufer space, and entering LISTEN state if to accept connections. ! 484: */ ! 485: int ! 486: tcp_attach(so) ! 487: struct socket *so; ! 488: { ! 489: register struct tcpcb *tp; ! 490: struct inpcb *inp; ! 491: int error; ! 492: ! 493: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { ! 494: error = soreserve(so, tcp_sendspace, tcp_recvspace); ! 495: if (error) ! 496: return (error); ! 497: } ! 498: ! 499: error = in_pcballoc(so, &tcb, &tcp_hash_str, &tcp_lport_hash_str); ! 500: if (error) ! 501: return (error); ! 502: ! 503: inp = sotoinpcb(so); ! 504: tp = tcp_newtcpcb(inp); ! 505: if (tp == 0) { ! 506: int nofd = so->so_state & SS_NOFDREF; /* XXX */ ! 507: ! 508: so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */ ! 509: in_pcbdetach(inp); ! 510: so->so_state |= nofd; ! 511: return (ENOBUFS); ! 512: } ! 513: tp->t_state = TCPS_CLOSED; ! 514: return (0); ! 515: } ! 516: ! 517: /* ! 518: * Initiate (or continue) disconnect. ! 519: * If embryonic state, just send reset (once). ! 520: * If in ``let data drain'' option and linger null, just drop. ! 521: * Otherwise (hard), mark socket disconnecting and drop ! 522: * current input data; switch states based on user close, and ! 523: * send segment to peer (with FIN). ! 524: */ ! 525: struct tcpcb * ! 526: tcp_disconnect(tp) ! 527: register struct tcpcb *tp; ! 528: { ! 529: struct socket *so = tp->t_inpcb->inp_socket; ! 530: ! 531: #if TEMPDEBUG ! 532: printf("TCP_DISCONNECT called for socket %x\n", so); ! 533: #endif ! 534: ! 535: if (tp->t_state < TCPS_ESTABLISHED) ! 536: tp = tcp_close(tp); ! 537: else if ((so->so_options & SO_LINGER) && so->so_linger == 0) ! 538: tp = tcp_drop(tp, 0); ! 539: else { ! 540: soisdisconnecting(so); ! 541: sbflush(&so->so_rcv); ! 542: tp = tcp_usrclosed(tp); ! 543: if (tp) ! 544: (void) tcp_output(tp); ! 545: } ! 546: return (tp); ! 547: } ! 548: ! 549: /* ! 550: * User issued close, and wish to trail through shutdown states: ! 551: * if never received SYN, just forget it. If got a SYN from peer, ! 552: * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. ! 553: * If already got a FIN from peer, then almost done; go to LAST_ACK ! 554: * state. In all other cases, have already sent FIN to peer (e.g. ! 555: * after PRU_SHUTDOWN), and just have to play tedious game waiting ! 556: * for peer to send FIN or not respond to keep-alives, etc. ! 557: * We can let the user exit from the close as soon as the FIN is acked. ! 558: */ ! 559: struct tcpcb * ! 560: tcp_usrclosed(tp) ! 561: register struct tcpcb *tp; ! 562: { ! 563: ! 564: switch (tp->t_state) { ! 565: ! 566: case TCPS_CLOSED: ! 567: case TCPS_LISTEN: ! 568: case TCPS_SYN_SENT: ! 569: tp->t_state = TCPS_CLOSED; ! 570: #if TEMPDEBUG ! 571: printf("TCP_USRCLOSED called for embryonic connection for socket %x\n", ! 572: tp->t_inpcb->inp_socket); ! 573: #endif ! 574: tp = tcp_close(tp); ! 575: break; ! 576: ! 577: case TCPS_SYN_RECEIVED: ! 578: case TCPS_ESTABLISHED: ! 579: #if DELACK_BITMASK_ON ! 580: current_active_connections--; ! 581: #endif ! 582: tp->t_state = TCPS_FIN_WAIT_1; ! 583: break; ! 584: ! 585: case TCPS_CLOSE_WAIT: ! 586: tp->t_state = TCPS_LAST_ACK; ! 587: break; ! 588: } ! 589: if (tp && tp->t_state >= TCPS_FIN_WAIT_2) ! 590: soisdisconnected(tp->t_inpcb->inp_socket); ! 591: return (tp); ! 592: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.