1 /* tcp_usrreq.c 1.34 81/11/24 */ 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 "../net/inet.h" 10 #include "../net/inet_pcb.h" 11 #include "../net/inet_systm.h" 12 #include "../net/if.h" 13 #include "../net/imp.h" 14 #include "../net/ip.h" 15 #include "../net/ip_var.h" 16 #include "../net/tcp.h" 17 #include "../net/tcp_fsm.h" 18 #include "../net/tcp_var.h" 19 #include "/usr/include/errno.h" 20 21 struct tcpcb *tcp_newtcpcb(); 22 /* 23 * Process a TCP user request for tcp tb. If this is a send request 24 * then m is the mbuf chain of send data. If this is a timer expiration 25 * (called from the software clock routine), then timertype tells which timer. 26 */ 27 tcp_usrreq(so, req, m, addr) 28 struct socket *so; 29 int req; 30 struct mbuf *m; 31 caddr_t addr; 32 { 33 register struct inpcb *inp = sotoinpcb(so); 34 register struct tcpcb *tp; 35 int s = splnet(); 36 register int nstate; 37 int error = 0; 38 COUNT(TCP_USRREQ); 39 40 /* 41 * Make sure attached. If not, 42 * only PRU_ATTACH is valid. 43 */ 44 if (inp == 0) { 45 if (req != PRU_ATTACH) { 46 splx(s); 47 return (EINVAL); 48 } 49 } else { 50 tp = intotcpcb(inp); 51 nstate = tp->t_state; 52 #ifdef KPROF 53 tcp_acounts[nstate][req]++; 54 #endif 55 } 56 57 switch (req) { 58 59 case PRU_ATTACH: 60 if (inp) { 61 error = EISCONN; 62 break; 63 } 64 error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr); 65 if (error) { 66 (void) m_free(dtom(tp)); 67 break; 68 } 69 inp = (struct inpcb *)so->so_pcb; 70 if (so->so_options & SO_ACCEPTCONN) { 71 tp = tcp_newtcpcb(inp); 72 if (tp == 0) { 73 error = ENOBUFS; 74 break; 75 } 76 nstate = LISTEN; 77 } else 78 nstate = CLOSED; 79 break; 80 81 case PRU_DETACH: 82 break; 83 84 case PRU_CONNECT: 85 error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr); 86 if (error) 87 break; 88 tp = tcp_newtcpcb(inp); 89 if (tp == 0) { 90 inp->inp_faddr.s_addr = 0; 91 error = ENOBUFS; 92 break; 93 } 94 tp->t_inpcb = inp; 95 inp->inp_ppcb = (caddr_t)tp; 96 (void) tcp_sndctl(tp); 97 nstate = SYN_SENT; 98 soisconnecting(so); 99 break; 100 101 case PRU_ACCEPT: 102 soisconnected(so); 103 break; 104 105 case PRU_DISCONNECT: 106 if (nstate < ESTAB) 107 tcp_disconnect(tp); 108 else { 109 tp->tc_flags |= TC_SND_FIN; 110 (void) tcp_sndctl(tp); 111 soisdisconnecting(so); 112 } 113 break; 114 115 case PRU_SHUTDOWN: 116 switch (nstate) { 117 118 case TCPS_LISTEN: 119 case TCPS_SYN_SENT: 120 nstate = TCPS_CLOSED; 121 break; 122 123 case TCPS_SYN_RCVD: 124 case TCPS_ESTABLISHED: 125 case TCPS_CLOSE_WAIT: 126 tp->tc_flags |= TC_SND_FIN; 127 (void) tcp_sndctl(tp); 128 nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK; 129 break; 130 131 case TCPS_FIN_W1: 132 case TCPS_FIN_W2: 133 case TCPS_TIME_WAIT: 134 case TCPS_CLOSING: 135 case TCPS_LAST_ACK: 136 case TCPS_RCV_WAIT: 137 break; 138 139 default: 140 goto bad; 141 } 142 break; 143 144 case PRU_RCVD: 145 if (nstate < TCPS_ESTAB) 146 goto bad; 147 tcp_sndwin(tp); 148 if (nstate == TCPS_RCV_WAIT && rcv_empty(tp)) 149 nstate = TCPS_CLOSED; 150 break; 151 152 case PRU_SEND: 153 switch (nstate) { 154 155 case ESTAB: 156 case CLOSE_WAIT: 157 tcp_usrsend(tp, m); 158 break; 159 160 default: 161 if (nstate < ESTAB) 162 goto bad; 163 m_freem(m); 164 error = ENOTCONN; 165 break; 166 } 167 break; 168 169 case PRU_ABORT: 170 tcp_abort(tp); 171 nstate = CLOSED; 172 break; 173 174 case PRU_CONTROL: 175 error = EOPNOTSUPP; 176 break; 177 178 case PRU_SLOWTIMO: 179 switch (nstate) { 180 181 case 0: 182 case CLOSED: 183 case LISTEN: 184 goto bad; 185 186 default: 187 nstate = tcp_timers(tp, (int)addr); 188 } 189 break; 190 191 default: 192 panic("tcp_usrreq"); 193 bad: 194 printf("tcp: bad state: tcb=%x state=%d input=%d\n", 195 tp, tp->t_state, req); 196 nstate = EFAILEC; 197 break; 198 } 199 switch (nstate) { 200 201 case CLOSED: 202 case SAME: 203 break; 204 205 case EFAILEC: 206 if (m) 207 m_freem(dtom(m)); 208 break; 209 210 default: 211 tp->t_state = nstate; 212 break; 213 } 214 splx(s); 215 return (error); 216 } 217 218 struct tcpcb * 219 tcp_newtcpcb(inp) 220 struct inpcb *inp; 221 { 222 struct mbuf *m = m_getclr(0); 223 register struct tcpcb *tp; 224 COUNT(TCP_NEWTCPCB); 225 226 if (m == 0) 227 return (0); 228 tp = mtod(m, struct tcpcb *); 229 230 /* 231 * Make empty reassembly queue. 232 */ 233 tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 234 235 /* 236 * Initialize sequence numbers and round trip retransmit timer. 237 */ 238 tp->t_xmtime = T_REXMT; 239 tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una = 240 tp->iss = tcp_iss; 241 tp->snd_off = tp->iss + 1; 242 tcp_iss += (ISSINCR >> 1) + 1; 243 244 /* 245 * Hook to inpcb. 246 */ 247 tp->t_inpcb = inp; 248 inp->inp_ppcb = (caddr_t)tp; 249 return (tp); 250 } 251 252 tcp_disconnect(tp) 253 register struct tcpcb *tp; 254 { 255 register struct tcpiphdr *t; 256 257 COUNT(TCP_DISCONNECT); 258 tcp_tcancel(tp); 259 t = tp->seg_next; 260 for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next) 261 m_freem(dtom(t)); 262 tcp_drainunack(tp); 263 if (tp->t_template) { 264 (void) m_free(dtom(tp->t_template)); 265 tp->t_template = 0; 266 } 267 in_pcbfree(tp->t_inpcb); 268 (void) m_free(dtom(tp)); 269 } 270 271 tcp_abort(tp) 272 register struct tcpcb *tp; 273 { 274 275 COUNT(TCP_ABORT); 276 switch (tp->t_state) { 277 278 case SYN_RCVD: 279 case ESTAB: 280 case FIN_W1: 281 case FIN_W2: 282 case CLOSE_WAIT: 283 tp->tc_flags |= TC_SND_RST; 284 tcp_sndnull(tp); 285 } 286 soisdisconnected(tp->t_inpcb->inp_socket); 287 tcp_disconnect(tp); 288 } 289 290 /* 291 * Send data queue headed by m0 into the protocol. 292 */ 293 tcp_usrsend(tp, m0) 294 register struct tcpcb *tp; 295 struct mbuf *m0; 296 { 297 register struct socket *so = tp->t_inpcb->inp_socket; 298 COUNT(TCP_USRSEND); 299 300 sbappend(&so->so_snd, m0); 301 if (tp->t_options & TO_EOL) 302 tp->snd_end = tp->snd_off + so->so_snd.sb_cc; 303 if (tp->t_options & TO_URG) { 304 tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1; 305 tp->tc_flags |= TC_SND_URG; 306 } 307 (void) tcp_send(tp); 308 } 309 310 /*ARGSUSED*/ 311 tcp_sense(m) 312 struct mbuf *m; 313 { 314 315 COUNT(TCP_SENSE); 316 return (EOPNOTSUPP); 317 } 318 319 tcp_drop(tp, errno) 320 struct tcpcb *tp; 321 int errno; 322 { 323 struct socket *so = tp->t_inpcb->inp_socket; 324 325 COUNT(TCP_ERROR); 326 so->so_error = errno; 327 sorwakeup(so); 328 sowwakeup(so); 329 tcp_disconnect(tp); 330 } 331 332 tcp_drain() 333 { 334 register struct inpcb *ip; 335 336 COUNT(TCP_DRAIN); 337 for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) 338 tcp_drainunack(intotcpcb(ip)); 339 } 340 341 tcp_drainunack(tp) 342 register struct tcpcb *tp; 343 { 344 register struct mbuf *m; 345 346 COUNT(TCP_DRAINUNACK); 347 for (m = tp->seg_unack; m; m = m->m_act) 348 m_freem(m); 349 tp->seg_unack = 0; 350 } 351 352 tcp_ctlinput(m) 353 struct mbuf *m; 354 { 355 356 COUNT(TCP_CTLINPUT); 357 m_freem(m); 358 } 359