|
|
1.1 ! root 1: /* tcp_usrreq.c 6.1 83/07/29 */ ! 2: ! 3: #include "../h/param.h" ! 4: #include "../h/systm.h" ! 5: #include "../h/mbuf.h" ! 6: #include "../h/socket.h" ! 7: #include "../h/socketvar.h" ! 8: #include "../h/protosw.h" ! 9: #include "../h/errno.h" ! 10: ! 11: #include "../net/if.h" ! 12: #include "../net/route.h" ! 13: ! 14: #include "../netinet/in.h" ! 15: #include "../netinet/in_pcb.h" ! 16: #include "../netinet/in_systm.h" ! 17: #include "../netinet/ip.h" ! 18: #include "../netinet/ip_var.h" ! 19: #include "../netinet/tcp.h" ! 20: #include "../netinet/tcp_fsm.h" ! 21: #include "../netinet/tcp_seq.h" ! 22: #include "../netinet/tcp_timer.h" ! 23: #include "../netinet/tcp_var.h" ! 24: #include "../netinet/tcpip.h" ! 25: #include "../netinet/tcp_debug.h" ! 26: ! 27: /* ! 28: * TCP protocol interface to socket abstraction. ! 29: */ ! 30: extern char *tcpstates[]; ! 31: struct tcpcb *tcp_newtcpcb(); ! 32: int tcpsenderrors; ! 33: ! 34: /* ! 35: * Process a TCP user request for TCP tb. If this is a send request ! 36: * then m is the mbuf chain of send data. If this is a timer expiration ! 37: * (called from the software clock routine), then timertype tells which timer. ! 38: */ ! 39: /*ARGSUSED*/ ! 40: tcp_usrreq(so, req, m, nam, rights) ! 41: struct socket *so; ! 42: int req; ! 43: struct mbuf *m, *nam, *rights; ! 44: { ! 45: register struct inpcb *inp = sotoinpcb(so); ! 46: register struct tcpcb *tp; ! 47: int s = splnet(); ! 48: int error = 0; ! 49: int ostate; ! 50: ! 51: if (rights && rights->m_len) { ! 52: splx(s); ! 53: return (EINVAL); ! 54: } ! 55: /* ! 56: * When a TCP is attached to a socket, then there will be ! 57: * a (struct inpcb) pointed at by the socket, and this ! 58: * structure will point at a subsidary (struct tcpcb). ! 59: */ ! 60: if (inp == 0 && req != PRU_ATTACH) { ! 61: splx(s); ! 62: return (EINVAL); /* XXX */ ! 63: } ! 64: if (inp) { ! 65: tp = intotcpcb(inp); ! 66: /* WHAT IF TP IS 0? */ ! 67: #ifdef KPROF ! 68: tcp_acounts[tp->t_state][req]++; ! 69: #endif ! 70: ostate = tp->t_state; ! 71: } else ! 72: ostate = 0; ! 73: switch (req) { ! 74: ! 75: /* ! 76: * TCP attaches to socket via PRU_ATTACH, reserving space, ! 77: * and an internet control block. ! 78: */ ! 79: case PRU_ATTACH: ! 80: if (inp) { ! 81: error = EISCONN; ! 82: break; ! 83: } ! 84: error = tcp_attach(so); ! 85: if (error) ! 86: break; ! 87: if ((so->so_options & SO_LINGER) && so->so_linger == 0) ! 88: so->so_linger = TCP_LINGERTIME; ! 89: tp = sototcpcb(so); ! 90: break; ! 91: ! 92: /* ! 93: * PRU_DETACH detaches the TCP protocol from the socket. ! 94: * If the protocol state is non-embryonic, then can't ! 95: * do this directly: have to initiate a PRU_DISCONNECT, ! 96: * which may finish later; embryonic TCB's can just ! 97: * be discarded here. ! 98: */ ! 99: case PRU_DETACH: ! 100: if (tp->t_state > TCPS_LISTEN) ! 101: tp = tcp_disconnect(tp); ! 102: else ! 103: tp = tcp_close(tp); ! 104: break; ! 105: ! 106: /* ! 107: * Give the socket an address. ! 108: */ ! 109: case PRU_BIND: ! 110: error = in_pcbbind(inp, nam); ! 111: if (error) ! 112: break; ! 113: break; ! 114: ! 115: /* ! 116: * Prepare to accept connections. ! 117: */ ! 118: case PRU_LISTEN: ! 119: if (inp->inp_lport == 0) ! 120: error = in_pcbbind(inp, (struct mbuf *)0); ! 121: if (error == 0) ! 122: tp->t_state = TCPS_LISTEN; ! 123: break; ! 124: ! 125: /* ! 126: * Initiate connection to peer. ! 127: * Create a template for use in transmissions on this connection. ! 128: * Enter SYN_SENT state, and mark socket as connecting. ! 129: * Start keep-alive timer, and seed output sequence space. ! 130: * Send initial segment on connection. ! 131: */ ! 132: case PRU_CONNECT: ! 133: if (inp->inp_lport == 0) { ! 134: error = in_pcbbind(inp, (struct mbuf *)0); ! 135: if (error) ! 136: break; ! 137: } ! 138: error = in_pcbconnect(inp, nam); ! 139: if (error) ! 140: break; ! 141: tp->t_template = tcp_template(tp); ! 142: if (tp->t_template == 0) { ! 143: in_pcbdisconnect(inp); ! 144: error = ENOBUFS; ! 145: break; ! 146: } ! 147: soisconnecting(so); ! 148: tp->t_state = TCPS_SYN_SENT; ! 149: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; ! 150: tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; ! 151: tcp_sendseqinit(tp); ! 152: error = tcp_output(tp); ! 153: break; ! 154: ! 155: /* ! 156: * Create a TCP connection between two sockets. ! 157: */ ! 158: case PRU_CONNECT2: ! 159: error = EOPNOTSUPP; ! 160: break; ! 161: ! 162: /* ! 163: * Initiate disconnect from peer. ! 164: * If connection never passed embryonic stage, just drop; ! 165: * else if don't need to let data drain, then can just drop anyways, ! 166: * else have to begin TCP shutdown process: mark socket disconnecting, ! 167: * drain unread data, state switch to reflect user close, and ! 168: * send segment (e.g. FIN) to peer. Socket will be really disconnected ! 169: * when peer sends FIN and acks ours. ! 170: * ! 171: * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. ! 172: */ ! 173: case PRU_DISCONNECT: ! 174: tp = tcp_disconnect(tp); ! 175: break; ! 176: ! 177: /* ! 178: * Accept a connection. Essentially all the work is ! 179: * done at higher levels; just return the address ! 180: * of the peer, storing through addr. ! 181: */ ! 182: case PRU_ACCEPT: { ! 183: struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); ! 184: ! 185: nam->m_len = sizeof (struct sockaddr_in); ! 186: sin->sin_family = AF_INET; ! 187: sin->sin_port = inp->inp_fport; ! 188: sin->sin_addr = inp->inp_faddr; ! 189: break; ! 190: } ! 191: ! 192: /* ! 193: * Mark the connection as being incapable of further output. ! 194: */ ! 195: case PRU_SHUTDOWN: ! 196: socantsendmore(so); ! 197: tp = tcp_usrclosed(tp); ! 198: if (tp) ! 199: error = tcp_output(tp); ! 200: break; ! 201: ! 202: /* ! 203: * After a receive, possibly send window update to peer. ! 204: */ ! 205: case PRU_RCVD: ! 206: (void) tcp_output(tp); ! 207: break; ! 208: ! 209: /* ! 210: * Do a send by putting data in output queue and updating urgent ! 211: * marker if URG set. Possibly send more data. ! 212: */ ! 213: case PRU_SEND: ! 214: sbappend(&so->so_snd, m); ! 215: #ifdef notdef ! 216: if (tp->t_flags & TF_PUSH) ! 217: tp->snd_end = tp->snd_una + so->so_snd.sb_cc; ! 218: #endif ! 219: error = tcp_output(tp); ! 220: if (error) { /* XXX fix to use other path */ ! 221: if (error == ENOBUFS) /* XXX */ ! 222: error = 0; /* XXX */ ! 223: tcpsenderrors++; ! 224: } ! 225: break; ! 226: ! 227: /* ! 228: * Abort the TCP. ! 229: */ ! 230: case PRU_ABORT: ! 231: tp = tcp_drop(tp, ECONNABORTED); ! 232: break; ! 233: ! 234: /* SOME AS YET UNIMPLEMENTED HOOKS */ ! 235: case PRU_CONTROL: ! 236: error = EOPNOTSUPP; ! 237: break; ! 238: ! 239: case PRU_SENSE: ! 240: error = EOPNOTSUPP; ! 241: break; ! 242: /* END UNIMPLEMENTED HOOKS */ ! 243: ! 244: case PRU_RCVOOB: ! 245: if (so->so_oobmark == 0 && ! 246: (so->so_state & SS_RCVATMARK) == 0) { ! 247: error = EINVAL; ! 248: break; ! 249: } ! 250: if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) { ! 251: error = EWOULDBLOCK; ! 252: break; ! 253: } ! 254: m->m_len = 1; ! 255: *mtod(m, caddr_t) = tp->t_iobc; ! 256: break; ! 257: ! 258: case PRU_SENDOOB: ! 259: if (sbspace(&so->so_snd) < -512) { ! 260: m_freem(m); ! 261: error = ENOBUFS; ! 262: break; ! 263: } ! 264: tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1; ! 265: sbappend(&so->so_snd, m); ! 266: tp->t_force = 1; ! 267: error = tcp_output(tp); ! 268: tp->t_force = 0; ! 269: break; ! 270: ! 271: case PRU_SOCKADDR: ! 272: in_setsockaddr(inp, nam); ! 273: break; ! 274: ! 275: case PRU_PEERADDR: ! 276: in_setpeeraddr(inp, nam); ! 277: break; ! 278: ! 279: /* ! 280: * TCP slow timer went off; going through this ! 281: * routine for tracing's sake. ! 282: */ ! 283: case PRU_SLOWTIMO: ! 284: tp = tcp_timers(tp, (int)nam); ! 285: req |= (int)nam << 8; /* for debug's sake */ ! 286: break; ! 287: ! 288: default: ! 289: panic("tcp_usrreq"); ! 290: } ! 291: if (tp && (so->so_options & SO_DEBUG)) ! 292: tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); ! 293: splx(s); ! 294: return (error); ! 295: } ! 296: ! 297: int tcp_sendspace = 1024*2; ! 298: int tcp_recvspace = 1024*2; ! 299: /* ! 300: * Attach TCP protocol to socket, allocating ! 301: * internet protocol control block, tcp control block, ! 302: * bufer space, and entering LISTEN state if to accept connections. ! 303: */ ! 304: tcp_attach(so) ! 305: struct socket *so; ! 306: { ! 307: register struct tcpcb *tp; ! 308: struct inpcb *inp; ! 309: int error; ! 310: ! 311: error = soreserve(so, tcp_sendspace, tcp_recvspace); ! 312: if (error) ! 313: goto bad; ! 314: error = in_pcballoc(so, &tcb); ! 315: if (error) ! 316: goto bad; ! 317: inp = sotoinpcb(so); ! 318: tp = tcp_newtcpcb(inp); ! 319: if (tp == 0) { ! 320: error = ENOBUFS; ! 321: goto bad2; ! 322: } ! 323: tp->t_state = TCPS_CLOSED; ! 324: return (0); ! 325: bad2: ! 326: in_pcbdetach(inp); ! 327: bad: ! 328: return (error); ! 329: } ! 330: ! 331: /* ! 332: * Initiate (or continue) disconnect. ! 333: * If embryonic state, just send reset (once). ! 334: * If in ``let data drain'' option and linger null, just drop. ! 335: * Otherwise (hard), mark socket disconnecting and drop ! 336: * current input data; switch states based on user close, and ! 337: * send segment to peer (with FIN). ! 338: */ ! 339: struct tcpcb * ! 340: tcp_disconnect(tp) ! 341: register struct tcpcb *tp; ! 342: { ! 343: struct socket *so = tp->t_inpcb->inp_socket; ! 344: ! 345: if (tp->t_state < TCPS_ESTABLISHED) ! 346: tp = tcp_close(tp); ! 347: else if ((so->so_options & SO_LINGER) && so->so_linger == 0) ! 348: tp = tcp_drop(tp, 0); ! 349: else { ! 350: soisdisconnecting(so); ! 351: sbflush(&so->so_rcv); ! 352: tp = tcp_usrclosed(tp); ! 353: if (tp) ! 354: (void) tcp_output(tp); ! 355: } ! 356: return (tp); ! 357: } ! 358: ! 359: /* ! 360: * User issued close, and wish to trail through shutdown states: ! 361: * if never received SYN, just forget it. If got a SYN from peer, ! 362: * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. ! 363: * If already got a FIN from peer, then almost done; go to LAST_ACK ! 364: * state. In all other cases, have already sent FIN to peer (e.g. ! 365: * after PRU_SHUTDOWN), and just have to play tedious game waiting ! 366: * for peer to send FIN or not respond to keep-alives, etc. ! 367: * We can let the user exit from the close as soon as the FIN is acked. ! 368: */ ! 369: struct tcpcb * ! 370: tcp_usrclosed(tp) ! 371: register struct tcpcb *tp; ! 372: { ! 373: ! 374: switch (tp->t_state) { ! 375: ! 376: case TCPS_CLOSED: ! 377: case TCPS_LISTEN: ! 378: case TCPS_SYN_SENT: ! 379: tp->t_state = TCPS_CLOSED; ! 380: tp = tcp_close(tp); ! 381: break; ! 382: ! 383: case TCPS_SYN_RECEIVED: ! 384: case TCPS_ESTABLISHED: ! 385: tp->t_state = TCPS_FIN_WAIT_1; ! 386: break; ! 387: ! 388: case TCPS_CLOSE_WAIT: ! 389: tp->t_state = TCPS_LAST_ACK; ! 390: break; ! 391: } ! 392: if (tp && tp->t_state >= TCPS_FIN_WAIT_2) ! 393: soisdisconnected(tp->t_inpcb->inp_socket); ! 394: return (tp); ! 395: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.