1 /* tcp_usrreq.c 1.10 81/10/23 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../bbnnet/net.h" 6 #include "../bbnnet/mbuf.h" 7 #include "../bbnnet/tcp.h" 8 #include "../bbnnet/ip.h" 9 #include "../bbnnet/imp.h" 10 #include "../bbnnet/ucb.h" 11 #define TCPFSTAB 12 #ifdef TCPDEBUG 13 #define TCPSTATES 14 #endif 15 #include "../bbnnet/fsm.h" 16 17 tcp_timeo() 18 { 19 register struct tcb *tp; 20 int s = splnet(); 21 COUNT(TCP_TIMEO); 22 23 /* 24 * Search through tcb's and update active timers. 25 */ 26 for (tp = netcb.n_tcb_head; tp != NULL; tp = tp->t_tcb_next) { 27 if (tp->t_init != 0 && --tp->t_init == 0) 28 tcp_usrreq(ISTIMER, TINIT, tp, 0); 29 if (tp->t_rexmt != 0 && --tp->t_rexmt == 0) 30 tcp_usrreq(ISTIMER, TREXMT, tp, 0); 31 if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0) 32 tcp_usrreq(ISTIMER, TREXMTTL, tp, 0); 33 if (tp->t_persist != 0 && --tp->t_persist == 0) 34 tcp_usrreq(ISTIMER, TPERSIST, tp, 0); 35 if (tp->t_finack != 0 && --tp->t_finack == 0) 36 tcp_usrreq(ISTIMER, TFINACK, tp, 0); 37 tp->t_xmt++; 38 } 39 netcb.n_iss += ISSINCR; /* increment iss */ 40 timeout(tcp_timeo, 0, hz); /* reschedule every second */ 41 splx(s); 42 } 43 44 tcp_usrreq(input, timertype, tp, mp) 45 int input, timertype; 46 register struct tcb *tp; 47 struct mbuf *mp; 48 { 49 int s = splnet(); 50 register int nstate; 51 #ifdef TCPDEBUG 52 struct tcp_debug tdb; 53 #endif 54 COUNT(TCP_USRREQ); 55 56 nstate = tp->t_state; 57 tp->tc_flags &= ~TC_NET_KEEP; 58 acounts[nstate][input]++; 59 #ifdef TCPDEBUG 60 if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 61 tdb.td_tod = time; 62 tdb.td_tcb = tp; 63 tdb.td_old = nstate; 64 tdb.td_inp = input; 65 tdb.td_tim = timertype; 66 } else 67 tdb.td_tod = 0; 68 #endif 69 switch (tcp_fstab[nstate][input]) { 70 71 default: 72 printf("tcp: bad state: tcb=%x state=%d input=%d\n", 73 tp, tp->t_state, input); 74 nstate = EFAILEC; 75 break; 76 77 case LIS_CLS: /* 1 */ 78 t_open(tp, PASSIVE); 79 nstate = LISTEN; 80 break; 81 82 case SYS_CLS: /* 2 */ 83 t_open(tp, ACTIVE); 84 send_ctl(tp); 85 nstate = SYN_SENT; 86 break; 87 88 case CLS_OPN: /* 10 */ 89 t_close(tp, UCLOSED); 90 nstate = CLOSED; 91 break; 92 93 case CL2_CLW: /* 10 */ 94 tp->tc_flags |= TC_SND_FIN; 95 send_ctl(tp); 96 tp->tc_flags |= TC_USR_CLOSED; 97 nstate = CLOSING2; 98 break; 99 100 case TIMERS: /* 14,17,34,35,36,37,38 */ 101 nstate = tcp_timers(tp, timertype); 102 break; 103 104 case CLS_RWT: /* 20 */ 105 present_data(tp); 106 if (rcv_empty(tp)) { 107 t_close(tp, UCLOSED); 108 nstate = CLOSED; 109 } else 110 nstate = RCV_WAIT; 111 break; 112 113 case FW1_SYR: /* 24,25 */ 114 tp->tc_flags |= TC_SND_FIN; 115 send_ctl(tp); 116 tp->tc_flags |= TC_USR_CLOSED; 117 nstate = FIN_W1; 118 break; 119 120 case SSS_SND: /* 40,41 */ 121 nstate = sss_snd(tp, mp); 122 break; 123 124 case SSS_RCV: /* 42 */ 125 send_ctl(tp); /* send new window */ 126 present_data(tp); 127 break; 128 129 case CLS_NSY: /* 44 */ 130 t_close(tp, UABORT); 131 nstate = CLOSED; 132 break; 133 134 case CLS_SYN: /* 45 */ 135 tp->tc_flags |= TC_SND_RST; 136 send_null(tp); 137 t_close(tp, UABORT); 138 nstate = CLOSED; 139 break; 140 141 case CLS_ACT: /* 47 */ 142 t_close(tp, UNETDWN); 143 nstate = CLOSED; 144 break; 145 146 case NOP: 147 break; 148 149 case CLS_ERR: 150 to_user(tp->t_ucb, UCLSERR); 151 break; 152 } 153 #ifdef TCPDEBUG 154 if (tdb.td_tod) { 155 tdb.td_new = nstate; 156 tcp_debug[tdbx++ % TDBSIZE] = tdb; 157 if (tcpconsdebug) 158 tcp_prt(&tdb); 159 } 160 #endif 161 /* YECH */ 162 switch (nstate) { 163 164 case CLOSED: 165 case SAME: 166 break; 167 168 case EFAILEC: 169 if (mp) 170 m_freem(dtom(mp)); 171 break; 172 173 default: 174 tp->t_state = nstate; 175 break; 176 } 177 splx(s); 178 } 179 180 t_open(tp, mode) /* set up a tcb for a connection */ 181 register struct tcb *tp; 182 int mode; 183 { 184 register struct ucb *up; 185 COUNT(T_OPEN); 186 187 /* enqueue the tcb */ 188 189 if (netcb.n_tcb_head == NULL) { 190 netcb.n_tcb_head = tp; 191 netcb.n_tcb_tail = tp; 192 } else { 193 tp->t_tcb_next = netcb.n_tcb_head; 194 netcb.n_tcb_head->t_tcb_prev = tp; 195 netcb.n_tcb_head = tp; 196 } 197 198 /* initialize non-zero tcb fields */ 199 200 tp->t_rcv_next = (struct th *)tp; 201 tp->t_rcv_prev = (struct th *)tp; 202 tp->t_xmtime = T_REXMT; 203 tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = 204 tp->snd_una = tp->iss = netcb.n_iss; 205 tp->snd_off = tp->iss + 1; 206 netcb.n_iss += (ISSINCR >> 1) + 1; 207 208 /* set timeout for open */ 209 210 up = tp->t_ucb; 211 tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo : 212 (mode == ACTIVE ? T_INIT : 0)); 213 up->uc_timeo = 0; /* overlays uc_ssize */ 214 } 215 216 t_close(tp, state) 217 register struct tcb *tp; 218 short state; 219 { 220 register struct ucb *up; 221 register struct th *t; 222 register struct mbuf *m; 223 COUNT(T_CLOSE); 224 225 up = tp->t_ucb; 226 227 tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist = 228 tp->t_finack = 0; 229 230 /* delete tcb */ 231 232 if (tp->t_tcb_prev == NULL) 233 netcb.n_tcb_head = tp->t_tcb_next; 234 else 235 tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next; 236 if (tp->t_tcb_next == NULL) 237 netcb.n_tcb_tail = tp->t_tcb_prev; 238 else 239 tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev; 240 241 /* free all data on receive and send buffers */ 242 243 for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 244 m_freem(dtom(t)); 245 246 if (up->uc_rbuf != NULL) { 247 m_freem(up->uc_rbuf); 248 up->uc_rbuf = NULL; 249 } 250 up->uc_rsize = 0; 251 if (up->uc_sbuf != NULL) { 252 m_freem(up->uc_sbuf); 253 up->uc_sbuf = NULL; 254 } 255 up->uc_ssize = 0; 256 for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 257 m_freem(m); 258 tp->t_rcv_unack = NULL; 259 } 260 m = dtom(tp); 261 m->m_off = 0; 262 m_free(m); 263 up->uc_tcb = NULL; 264 265 /* lower buffer allocation and decrement host entry */ 266 267 netcb.n_lowat -= up->uc_snd + up->uc_rcv + 2; 268 netcb.n_hiwat = 2 * netcb.n_lowat; 269 if (up->uc_host != NULL) { 270 h_free(up->uc_host); 271 up->uc_host = NULL; 272 } 273 274 /* if user has initiated close (via close call), delete ucb 275 entry, otherwise just wakeup so user can issue close call */ 276 277 if (tp->tc_flags&TC_USR_ABORT) 278 up->uc_proc = NULL; 279 else 280 to_user(up, state); 281 } 282 283 sss_snd(tp, m0) 284 register struct tcb *tp; 285 struct mbuf *m0; 286 { 287 register struct mbuf *m, *n; 288 register struct ucb *up = tp->t_ucb; 289 register off; 290 seq_t last; 291 292 last = tp->snd_off; 293 for (m = n = m0; m != NULL; m = m->m_next) { 294 up->uc_ssize++; 295 if (m->m_off > MMAXOFF) 296 up->uc_ssize += NMBPG; 297 last += m->m_len; 298 } 299 if ((m = up->uc_sbuf) == NULL) 300 up->uc_sbuf = n; 301 else { 302 while (m->m_next != NULL) { 303 m = m->m_next; 304 last += m->m_len; 305 } 306 if (m->m_off <= MMAXOFF) { 307 last += m->m_len; 308 off = m->m_off + m->m_len; 309 while (n && n->m_off <= MMAXOFF && 310 (MMAXOFF - off) >= n->m_len) { 311 bcopy((caddr_t)((int)n + n->m_off), 312 (caddr_t)((int)m + off), n->m_len); 313 m->m_len += n->m_len; 314 off += n->m_len; 315 up->uc_ssize--; 316 n = m_free(n); 317 } 318 } 319 m->m_next = n; 320 } 321 if (up->uc_flags & UEOL) 322 tp->snd_end = last; 323 if (up->uc_flags & UURG) { 324 tp->snd_urp = last+1; 325 tp->tc_flags |= TC_SND_URG; 326 } 327 send(tp); 328 return (SAME); 329 } 330 331 tcp_timers(tp, timertype) 332 register struct tcb *tp; 333 int timertype; 334 { 335 336 COUNT(TCP_TIMERS); 337 switch (timertype) { 338 339 case TINIT: /* initialization timer */ 340 if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ 341 t_close(tp, UINTIMO); 342 return (CLOSED); 343 } 344 return (SAME); 345 346 case TFINACK: /* fin-ack timer */ 347 switch (tp->t_state) { 348 349 case TIME_WAIT: 350 /* 351 * We can be sure our ACK of foreign FIN was rcvd, 352 * and can close if no data left for user. 353 */ 354 if (rcv_empty(tp)) { 355 t_close(tp, UCLOSED); /* 14 */ 356 return (CLOSED); 357 } 358 return (RCV_WAIT); /* 17 */ 359 360 case CLOSING1: 361 tp->tc_flags |= TC_WAITED_2_ML; 362 return (SAME); 363 364 default: 365 return (SAME); 366 } 367 368 case TREXMT: /* retransmission timer */ 369 if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 370 /* 371 * Set up for a retransmission, increase rexmt time 372 * in case of multiple retransmissions. 373 */ 374 tp->snd_nxt = tp->snd_una; 375 tp->tc_flags |= TC_REXMT; 376 tp->t_xmtime = tp->t_xmtime << 1; 377 if (tp->t_xmtime > T_REMAX) 378 tp->t_xmtime = T_REMAX; 379 send(tp); 380 } 381 return (SAME); 382 383 case TREXMTTL: /* retransmit too long */ 384 if (tp->t_rtl_val > tp->snd_una) /* 36 */ 385 to_user(tp->t_ucb, URXTIMO); 386 /* 387 * If user has already closed, abort the connection. 388 */ 389 if (tp->tc_flags & TC_USR_CLOSED) { 390 t_close(tp, URXTIMO); 391 return (CLOSED); 392 } 393 return (SAME); 394 395 case TPERSIST: /* persist timer */ 396 /* 397 * Force a byte send through closed window. 398 */ 399 tp->tc_flags |= TC_FORCE_ONE; 400 send(tp); 401 return (SAME); 402 } 403 panic("tcp_timers"); 404 } 405 406 /* THIS ROUTINE IS A CROCK */ 407 to_user(up, state) 408 register struct ucb *up; 409 register short state; 410 { 411 COUNT(TO_USER); 412 413 up->uc_state |= state; 414 netwakeup(up); 415 if (state == UURGENT) 416 psignal(up->uc_proc, SIGURG); 417 } 418 419 #ifdef TCPDEBUG 420 tcp_prt(tdp) 421 register struct tcp_debug *tdp; 422 { 423 COUNT(TCP_PRT); 424 425 printf("TCP(%X) %s X %s", 426 tdp->td_tcb, tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 427 if (tdp->td_inp == ISTIMER) 428 printf("(%s)", tcptimers[tdp->td_tim]); 429 printf(" --> %s", 430 tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 431 /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 432 if (tdp->td_new < 0) 433 printf(" (FAILED)"); 434 printf("\n"); 435 } 436 #endif 437