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