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