1 /* tcp_usrreq.c 1.9 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 if (up->uc_sbuf != NULL) { 251 m_freem(up->uc_sbuf); 252 up->uc_sbuf = NULL; 253 } 254 for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 255 m_freem(m); 256 tp->t_rcv_unack = NULL; 257 } 258 m = dtom(tp); 259 m->m_off = 0; 260 m_free(m); 261 up->uc_tcb = NULL; 262 263 /* lower buffer allocation and decrement host entry */ 264 265 netcb.n_lowat -= up->uc_snd + up->uc_rcv + 2; 266 netcb.n_hiwat = 2 * netcb.n_lowat; 267 if (up->uc_host != NULL) { 268 h_free(up->uc_host); 269 up->uc_host = NULL; 270 } 271 272 /* if user has initiated close (via close call), delete ucb 273 entry, otherwise just wakeup so user can issue close call */ 274 275 if (tp->tc_flags&TC_USR_ABORT) 276 up->uc_proc = NULL; 277 else 278 to_user(up, state); 279 } 280 281 sss_snd(tp, m0) 282 register struct tcb *tp; 283 struct mbuf *m0; 284 { 285 register struct mbuf *m, *n; 286 register struct ucb *up = tp->t_ucb; 287 register off; 288 seq_t last; 289 290 last = tp->snd_off; 291 for (m = n = m0; m != NULL; m = m->m_next) { 292 up->uc_ssize++; 293 if (m->m_off > MMAXOFF) 294 up->uc_ssize += NMBPG; 295 last += m->m_len; 296 } 297 if ((m = up->uc_sbuf) == NULL) 298 up->uc_sbuf = n; 299 else { 300 while (m->m_next != NULL) { 301 m = m->m_next; 302 last += m->m_len; 303 } 304 if (m->m_off <= MMAXOFF) { 305 last += m->m_len; 306 off = m->m_off + m->m_len; 307 while (n && n->m_off <= MMAXOFF && 308 (MMAXOFF - off) >= n->m_len) { 309 bcopy((caddr_t)((int)n + n->m_off), 310 (caddr_t)((int)m + off), n->m_len); 311 m->m_len += n->m_len; 312 off += n->m_len; 313 up->uc_ssize--; 314 n = m_free(n); 315 } 316 } 317 m->m_next = n; 318 } 319 if (up->uc_flags & UEOL) 320 tp->snd_end = last; 321 if (up->uc_flags & UURG) { 322 tp->snd_urp = last+1; 323 tp->tc_flags |= TC_SND_URG; 324 } 325 send(tp); 326 return (SAME); 327 } 328 329 tcp_timers(tp, timertype) 330 register struct tcb *tp; 331 int timertype; 332 { 333 334 COUNT(TCP_TIMERS); 335 switch (timertype) { 336 337 case TINIT: /* initialization timer */ 338 if ((tp->tc_flags&TC_SYN_ACKED) == 0) { /* 35 */ 339 t_close(tp, UINTIMO); 340 return (CLOSED); 341 } 342 return (SAME); 343 344 case TFINACK: /* fin-ack timer */ 345 switch (tp->t_state) { 346 347 case TIME_WAIT: 348 /* 349 * We can be sure our ACK of foreign FIN was rcvd, 350 * and can close if no data left for user. 351 */ 352 if (rcv_empty(tp)) { 353 t_close(tp, UCLOSED); /* 14 */ 354 return (CLOSED); 355 } 356 return (RCV_WAIT); /* 17 */ 357 358 case CLOSING1: 359 tp->tc_flags |= TC_WAITED_2_ML; 360 return (SAME); 361 362 default: 363 return (SAME); 364 } 365 366 case TREXMT: /* retransmission timer */ 367 if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 368 /* 369 * Set up for a retransmission, increase rexmt time 370 * in case of multiple retransmissions. 371 */ 372 tp->snd_nxt = tp->snd_una; 373 tp->tc_flags |= TC_REXMT; 374 tp->t_xmtime = tp->t_xmtime << 1; 375 if (tp->t_xmtime > T_REMAX) 376 tp->t_xmtime = T_REMAX; 377 send(tp); 378 } 379 return (SAME); 380 381 case TREXMTTL: /* retransmit too long */ 382 if (tp->t_rtl_val > tp->snd_una) /* 36 */ 383 to_user(tp->t_ucb, URXTIMO); 384 /* 385 * If user has already closed, abort the connection. 386 */ 387 if (tp->tc_flags & TC_USR_CLOSED) { 388 t_close(tp, URXTIMO); 389 return (CLOSED); 390 } 391 return (SAME); 392 393 case TPERSIST: /* persist timer */ 394 /* 395 * Force a byte send through closed window. 396 */ 397 tp->tc_flags |= TC_FORCE_ONE; 398 send(tp); 399 return (SAME); 400 } 401 panic("tcp_timers"); 402 } 403 404 /* THIS ROUTINE IS A CROCK */ 405 to_user(up, state) 406 register struct ucb *up; 407 register short state; 408 { 409 COUNT(TO_USER); 410 411 up->uc_state |= state; 412 netwakeup(up); 413 if (state == UURGENT) 414 psignal(up->uc_proc, SIGURG); 415 } 416 417 #ifdef TCPDEBUG 418 tcp_prt(tdp) 419 register struct tcp_debug *tdp; 420 { 421 COUNT(TCP_PRT); 422 423 printf("TCP(%X) %s X %s", 424 tdp->td_tcb, tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]); 425 if (tdp->td_inp == ISTIMER) 426 printf("(%s)", tcptimers[tdp->td_tim]); 427 printf(" --> %s", 428 tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]); 429 /* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */ 430 if (tdp->td_new < 0) 431 printf(" (FAILED)"); 432 printf("\n"); 433 } 434 #endif 435