1 /* tcp_usrreq.c 1.4 81/10/21 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../bbnnet/net.h" 6 #include "../bbnnet/tcp.h" 7 #include "../bbnnet/ip.h" 8 #include "../bbnnet/imp.h" 9 #include "../bbnnet/ucb.h" 10 #define TCPFSTAB 11 #include "../bbnnet/fsm.h" 12 #include "../bbnnet/tcp_pred.h" 13 14 /* 15 * This file contains the top level routines for actions 16 * called by the user and by the clock routines, while input 17 * actions for network data are driven by tcp_input. The two 18 * main entry points here are tcp_timeo, which decrements tcp timers 19 * each second and runs timer action routines when the timers go off, 20 * and tcp_usrreq, which performs requests generated by or on behalf 21 * of user processes. Both routines raise the ipl to splnet to block 22 * off tcp_input processing (triggered by imp's) during the work 23 * here. 24 */ 25 26 tcp_timeo() 27 { 28 register struct tcb *tp; 29 int s = splnet(); 30 COUNT(TCP_TIMEO); 31 32 /* 33 * Search through tcb's and update active timers. 34 */ 35 for (tp = netcb.n_tcb_head; tp != NULL; tp = tp->t_tcb_next) { 36 if (tp->t_init != 0 && --tp->t_init == 0) 37 tcp_usrreq(ISTIMER, TINIT, tp, 0); 38 if (tp->t_rexmt != 0 && --tp->t_rexmt == 0) 39 tcp_usrreq(ISTIMER, TREXMT, tp, 0); 40 if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0) 41 tcp_usrreq(ISTIMER, TREXMTTL, tp, 0); 42 if (tp->t_persist != 0 && --tp->t_persist == 0) 43 tcp_usrreq(ISTIMER, TPERSIST, tp, 0); 44 if (tp->t_finack != 0 && --tp->t_finack == 0) 45 tcp_usrreq(ISTIMER, TFINACK, tp, 0); 46 tp->t_xmt++; 47 } 48 netcb.n_iss += ISSINCR; /* increment iss */ 49 timeout(tcp_timeo, 0, hz); /* reschedule every second */ 50 splx(s); 51 } 52 53 tcp_usrreq(input, stype, tp, m) 54 int input, stype; 55 register struct tcb *tp; 56 char *m; 57 { 58 struct work w; 59 int s = splnet(); 60 register int nstate; 61 register struct work *wp = &w; 62 COUNT(TCP_USRREQ); 63 64 wp->w_type = input; 65 wp->w_stype = stype; 66 wp->w_tcb = tp; 67 wp->w_dat = m; 68 nstate = tp->t_state; 69 tp->net_keep = 0; 70 acounts[nstate][input]++; 71 switch (tcp_fstab[nstate][input]) { 72 73 default: 74 printf("tcp: bad state: tcb=%x state=%d input=%d\n", 75 tp, tp->t_state, input); 76 nstate = EFAILEC; 77 break; 78 79 case LIS_CLS: /* 1 */ 80 t_open(tp, PASSIVE); 81 nstate = LISTEN; 82 break; 83 84 case SYS_CLS: /* 2 */ 85 t_open(tp, ACTIVE); 86 send_ctl(tp); 87 nstate = SYN_SENT; 88 break; 89 90 case CLS_OPN: /* 10 */ 91 t_close(tp, UCLOSED); 92 nstate = CLOSED; 93 break; 94 95 case CL2_CLW: /* 10 */ 96 tp->snd_fin = 1; 97 send_ctl(tp); 98 tp->usr_closed = 1; 99 nstate = CLOSING2; 100 break; 101 102 case TIMERS: /* 14,17,34,35,36,37,38 */ 103 nstate = tcp_timers(wp); 104 break; 105 106 case CLS_RWT: /* 20 */ 107 present_data(tp); 108 if (rcv_empty(tp)) { 109 t_close(tp, UCLOSED); 110 nstate = CLOSED; 111 } else 112 nstate = RCV_WAIT; 113 break; 114 115 case FW1_SYR: /* 24,25 */ 116 tp->snd_fin = 1; 117 send_ctl(tp); 118 tp->usr_closed = 1; 119 nstate = FIN_W1; 120 break; 121 122 case SSS_SND: /* 40,41 */ 123 nstate = sss_snd(wp); 124 break; 125 126 case SSS_RCV: /* 42 */ 127 send_ctl(tp); /* send new window */ 128 present_data(tp); 129 break; 130 131 case CLS_NSY: /* 44 */ 132 t_close(tp, UABORT); 133 nstate = CLOSED; 134 break; 135 136 case CLS_SYN: /* 45 */ 137 tp->snd_rst = 1; 138 send_null(tp); 139 t_close(tp, UABORT); 140 nstate = CLOSED; 141 break; 142 143 case CLS_ACT: /* 47 */ 144 t_close(tp, UNETDWN); 145 nstate = CLOSED; 146 break; 147 148 case NOP: 149 break; 150 151 case CLS_ERR: 152 to_user(tp->t_ucb, UCLSERR); 153 break; 154 } 155 if (tp->t_ucb->uc_flags & UDEBUG) 156 tcp_debug(tp, wp, input, nstate); 157 #ifdef TCPDEBUG 158 tcp_prt(tp, input, wp->w_stype, nstate); 159 #endif 160 /* YECH */ 161 switch (nstate) { 162 163 case SAME: 164 break; 165 166 case EFAILEC: 167 if (m) 168 m_freem(dtom(m)); 169 break; 170 171 default: 172 tp->t_state = nstate; 173 break; 174 } 175 splx(s); 176 } 177 178 t_open(tp, mode) /* set up a tcb for a connection */ 179 register struct tcb *tp; 180 int mode; 181 { 182 register struct ucb *up; 183 COUNT(T_OPEN); 184 185 /* enqueue the tcb */ 186 187 if (netcb.n_tcb_head == NULL) { 188 netcb.n_tcb_head = tp; 189 netcb.n_tcb_tail = tp; 190 } else { 191 tp->t_tcb_next = netcb.n_tcb_head; 192 netcb.n_tcb_head->t_tcb_prev = tp; 193 netcb.n_tcb_head = tp; 194 } 195 196 /* initialize non-zero tcb fields */ 197 198 tp->t_rcv_next = (struct th *)tp; 199 tp->t_rcv_prev = (struct th *)tp; 200 tp->t_xmtime = T_REXMT; 201 tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = 202 tp->snd_una = tp->iss = netcb.n_iss; 203 tp->snd_off = tp->iss + 1; 204 netcb.n_iss += (ISSINCR >> 1) + 1; 205 206 /* set timeout for open */ 207 208 up = tp->t_ucb; 209 tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo : 210 (mode == ACTIVE ? T_INIT : 0)); 211 up->uc_timeo = 0; /* overlays uc_ssize */ 212 } 213 214 t_close(tp, state) 215 register struct tcb *tp; 216 short state; 217 { 218 register struct ucb *up; 219 register struct th *t; 220 register struct mbuf *m; 221 register struct work *w; 222 COUNT(T_CLOSE); 223 224 up = tp->t_ucb; 225 226 tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist = 227 tp->t_finack = 0; 228 229 /* delete tcb */ 230 231 if (tp->t_tcb_prev == NULL) 232 netcb.n_tcb_head = tp->t_tcb_next; 233 else 234 tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next; 235 if (tp->t_tcb_next == NULL) 236 netcb.n_tcb_tail = tp->t_tcb_prev; 237 else 238 tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev; 239 240 /* free all data on receive and send buffers */ 241 242 for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next) 243 m_freem(dtom(t)); 244 245 if (up->uc_rbuf != NULL) { 246 m_freem(up->uc_rbuf); 247 up->uc_rbuf = NULL; 248 } 249 if (up->uc_sbuf != NULL) { 250 m_freem(up->uc_sbuf); 251 up->uc_sbuf = NULL; 252 } 253 for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) { 254 m_freem(m); 255 tp->t_rcv_unack = NULL; 256 } 257 m_free(dtom(tp)); 258 up->uc_tcb = NULL; 259 260 /* lower buffer allocation and decrement host entry */ 261 262 netcb.n_lowat -= up->uc_snd + up->uc_rcv + 2; 263 netcb.n_hiwat = 2 * netcb.n_lowat; 264 if (up->uc_host != NULL) { 265 h_free(up->uc_host); 266 up->uc_host = NULL; 267 } 268 269 /* if user has initiated close (via close call), delete ucb 270 entry, otherwise just wakeup so user can issue close call */ 271 272 if (tp->usr_abort) 273 up->uc_proc = NULL; 274 else 275 to_user(up, state); 276 277 } 278 279 sss_snd(wp) 280 struct work *wp; 281 { 282 register struct tcb *tp; 283 register struct mbuf *m, *n; 284 register struct ucb *up; 285 register off; 286 sequence last; 287 288 tp = wp->w_tcb; 289 up = tp->t_ucb; 290 291 last = tp->snd_off; 292 293 /* count number of mbufs in send data */ 294 295 for (m = n = (struct mbuf *)wp->w_dat; m != NULL; m = m->m_next) { 296 up->uc_ssize++; 297 last += m->m_len; 298 } 299 300 /* find end of send buffer and append data */ 301 302 if ((m = up->uc_sbuf) != NULL) { /* something in send buffer */ 303 while (m->m_next != NULL) { /* find the end */ 304 m = m->m_next; 305 last += m->m_len; 306 } 307 last += m->m_len; 308 309 /* if there's room in old buffer for new data, consolidate */ 310 311 off = m->m_off + m->m_len; 312 while (n != NULL && (MSIZE - off) >= n->m_len) { 313 bcopy((caddr_t)((int)n + n->m_off), 314 (caddr_t)((int)m + off), n->m_len); 315 m->m_len += n->m_len; 316 off += n->m_len; 317 up->uc_ssize--; 318 n = m_free(n); 319 } 320 m->m_next = n; 321 322 } else /* nothing in send buffer */ 323 up->uc_sbuf = n; 324 325 if (up->uc_flags & UEOL) { /* set EOL */ 326 tp->snd_end = last; 327 } 328 329 if (up->uc_flags & UURG) { /* urgent data */ 330 tp->snd_urp = last+1; 331 tp->snd_urg = 1; 332 } 333 334 send(tp); 335 336 return (SAME); 337 } 338 339 tcp_timers(wp) 340 struct work *wp; 341 { 342 register struct tcb *tp = wp->w_tcb; 343 register type = wp->w_stype; 344 345 COUNT(TCP_TIMERS); 346 switch (type) { 347 348 case TINIT: /* initialization timer */ 349 if (!tp->syn_acked) { /* 35 */ 350 t_close(tp, UINTIMO); 351 return (CLOSED); 352 } 353 return (SAME); 354 355 case TFINACK: /* fin-ack timer */ 356 switch (tp->t_state) { 357 358 case TIME_WAIT: 359 /* 360 * We can be sure our ACK of foreign FIN was rcvd, 361 * and can close if no data left for user. 362 */ 363 if (rcv_empty(tp)) { 364 t_close(tp, UCLOSED); /* 14 */ 365 return (CLOSED); 366 } 367 return (RCV_WAIT); /* 17 */ 368 369 case CLOSING1: 370 tp->waited_2_ml = 1; 371 return (SAME); 372 373 default: 374 return (SAME); 375 } 376 377 case TREXMT: /* retransmission timer */ 378 if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 379 /* 380 * Set up for a retransmission, increase rexmt time 381 * in case of multiple retransmissions. 382 */ 383 tp->snd_nxt = tp->snd_una; 384 tp->rexmt = 1; 385 tp->t_xmtime = tp->t_xmtime << 1; 386 if (tp->t_xmtime > T_REMAX) 387 tp->t_xmtime = T_REMAX; 388 send(tp); 389 } 390 return (SAME); 391 392 case TREXMTTL: /* retransmit too long */ 393 if (tp->t_rtl_val > tp->snd_una) /* 36 */ 394 to_user(tp->t_ucb, URXTIMO); 395 /* 396 * If user has already closed, abort the connection. 397 */ 398 if (tp->usr_closed) { 399 t_close(tp, URXTIMO); 400 return (CLOSED); 401 } 402 return (SAME); 403 404 case TPERSIST: /* persist timer */ 405 /* 406 * Force a byte send through closed window. 407 */ 408 tp->force_one = 1; /* 38 */ 409 send(tp); 410 return (SAME); 411 } 412 panic("tcp_timers"); 413 } 414 415 tcp_debug(tp, wp, input, newstate) /* write a debugging record */ 416 register struct tcb *tp; 417 register struct work *wp; 418 int input, newstate; 419 { 420 struct t_debug debuf; 421 register struct th *n; 422 register off_t siz; 423 COUNT(TCP_DEBUG); 424 425 /* look for debugging file inode */ 426 427 if (netcb.n_debug == 0) 428 return; 429 debuf.t_tod = time; 430 if ((debuf.t_tcb = tp) != NULL) 431 debuf.t_old = tp->t_state; 432 else 433 debuf.t_old = 0; 434 debuf.t_inp = input; 435 debuf.t_tim = wp->w_stype; 436 debuf.t_new = newstate; 437 if (input == INRECV) { 438 n = (struct th *)wp->w_dat; 439 debuf.t_sno = n->t_seq; 440 debuf.t_ano = n->t_ackno; 441 debuf.t_wno = n->t_win; 442 if (debuf.t_new == -1) 443 debuf.t_lno = ((struct ip *)n)->ip_len; 444 else 445 debuf.t_lno = n->t_len; 446 debuf.t_flg = *(char *)((int)&n->t_win - 1); 447 } 448 /* STUFF INTO CIRC BUFFER */ 449 } 450 451 #ifdef TCPDEBUG 452 453 tcp_prt(tp, input, timer, newstate) /* print debugging info on the console */ 454 register struct tcb *tp; 455 register input, timer, newstate; 456 { 457 register oldstate; 458 COUNT(TCP_PRT); 459 460 oldstate = tp->t_state; 461 printf("TCP(%X) %s X %s", tp, tcpstates[oldstate], tcpinputs[input]); 462 if (input == ISTIMER) 463 printf("(%s)", tcptimers[timer]); 464 printf(" --> %s", tcpstates[ (newstate > 0) ? newstate : oldstate ]); 465 if (newstate < 0) 466 printf(" (FAILED)\n"); 467 else 468 putchar('\n'); 469 } 470 #endif 471 472 /* THIS ROUTINE IS A CROCK */ 473 to_user(up, state) 474 register struct ucb *up; 475 register short state; 476 { 477 COUNT(TO_USER); 478 479 up->uc_state |= state; 480 netwakeup(up); 481 if (state == UURGENT) 482 psignal(up->uc_proc, SIGURG); 483 } 484