1*4603Sroot /* tcp_input.c 1.2 81/10/25 */ 24601Swnj 34601Swnj #include "../h/param.h" 44601Swnj #include "../h/systm.h" 54601Swnj #include "../bbnnet/net.h" 64601Swnj #include "../bbnnet/mbuf.h" 74601Swnj #include "../bbnnet/host.h" 84601Swnj #include "../bbnnet/imp.h" 94601Swnj #include "../bbnnet/ucb.h" 104601Swnj #include "../bbnnet/tcp.h" 114601Swnj #include "../bbnnet/ip.h" 124601Swnj #include "../h/dir.h" 134601Swnj #include "../h/user.h" 144601Swnj #include "../h/inode.h" 154601Swnj #include "../bbnnet/fsm.h" 164601Swnj 174601Swnj extern int nosum; 184601Swnj 194601Swnj tcp_input(mp) 204601Swnj register struct mbuf *mp; 214601Swnj { 224601Swnj register struct tcb *tp; 234601Swnj register struct th *n; 244601Swnj int nstate; 254601Swnj struct mbuf *m; 264601Swnj struct ucb *up; 274601Swnj int hlen, tlen, j; 284601Swnj u_short lport, fport; 294601Swnj #ifdef TCPDEBUG 304601Swnj struct tcp_debug tdb; 314601Swnj #endif 324601Swnj COUNT(TCP_INPUT); 334601Swnj 344601Swnj /* 354601Swnj * Build extended tcp header 364601Swnj */ 374601Swnj n = (struct th *)((int)mp + mp->m_off); 384601Swnj tlen = ((struct ip *)n)->ip_len; 394601Swnj n->t_len = htons(tlen); 404601Swnj n->t_next = NULL; 414601Swnj n->t_prev = NULL; 424601Swnj n->t_x1 = 0; 434601Swnj lport = ntohs(n->t_dst); 444601Swnj fport = ntohs(n->t_src); 454601Swnj 464601Swnj /* WONT BE POSSIBLE WHEN MBUFS ARE 256 BYTES */ 474601Swnj if ((hlen = n->t_off << 2) > mp->m_len) 484601Swnj { printf("tcp header overflow\n"); m_freem(mp); return; } 494601Swnj 504601Swnj /* 514601Swnj * Checksum extended header and data 524601Swnj */ 534601Swnj j = n->t_sum; n->t_sum = 0; 544601Swnj if (j != cksum(mp, sizeof (struct ip) + tlen)) { 554601Swnj netstat.t_badsum++; 564601Swnj if (nosum == 0) { 574601Swnj m_freem(mp); 584601Swnj return; 594601Swnj } 604601Swnj } 614601Swnj 624601Swnj /* 634601Swnj * Find tcb for message (SHOULDN'T USE LINEAR SEARCH!) 644601Swnj */ 654601Swnj for (tp = netcb.n_tcb_head; tp != 0; tp = tp->t_tcb_next) 664601Swnj if (tp->t_lport == lport && tp->t_fport == fport && 674601Swnj tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr) 684601Swnj goto found; 694601Swnj for (tp = netcb.n_tcb_head; tp != 0; tp = tp->t_tcb_next) 704601Swnj if (tp->t_lport == lport && 714601Swnj (tp->t_fport==fport || tp->t_fport==0) && 724601Swnj (tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr || 734601Swnj tp->t_ucb->uc_host->h_addr.s_addr == 0)) 744601Swnj goto found; 754601Swnj goto notwanted; 764601Swnj found: 774601Swnj 784601Swnj /* 794601Swnj * Byte swap header 804601Swnj */ 814601Swnj n->t_len = tlen - hlen; 824601Swnj n->t_src = fport; 834601Swnj n->t_dst = lport; 844601Swnj n->t_seq = ntohl(n->t_seq); 854601Swnj n->t_ackno = ntohl(n->t_ackno); 864601Swnj n->t_win = ntohs(n->t_win); 874601Swnj n->t_urp = ntohs(n->t_urp); 884601Swnj 894601Swnj /* 904601Swnj * Check segment seq # and do rst processing 914601Swnj */ 924601Swnj switch (tp->t_state) { 934601Swnj 944601Swnj case LISTEN: 954601Swnj if ((n->th_flags&TH_ACK) || !syn_ok(tp, n)) { 964601Swnj send_rst(tp, n); 974601Swnj goto badseg; 984601Swnj } 994601Swnj if (n->th_flags&TH_RST) 1004601Swnj goto badseg; 1014601Swnj goto goodseg; 1024601Swnj 1034601Swnj case SYN_SENT: 1044601Swnj if (!ack_ok(tp, n) || !syn_ok(tp, n)) { 1054601Swnj send_rst(tp, n); /* 71,72,75 */ 1064601Swnj goto badseg; 1074601Swnj } 1084601Swnj if (n->th_flags&TH_RST) { 1094601Swnj t_close(tp, URESET); /* 70 */ 1104601Swnj tp->t_state = CLOSED; 1114601Swnj goto badseg; 1124601Swnj } 1134601Swnj goto goodseg; 1144601Swnj 1154601Swnj default: 1164601Swnj if ((n->th_flags&TH_RST) == 0) 1174601Swnj goto common; 1184601Swnj if (n->t_seq < tp->rcv_nxt) /* bad rst */ 1194601Swnj goto badseg; /* 69 */ 1204601Swnj switch (tp->t_state) { 1214601Swnj 1224601Swnj case L_SYN_RCVD: 1234601Swnj if (ack_ok(tp, n) == 0) 1244601Swnj goto badseg; /* 69 */ 1254601Swnj tp->t_rexmt = 0; 1264601Swnj tp->t_rexmttl = 0; 1274601Swnj tp->t_persist = 0; 1284601Swnj h_free(tp->t_ucb->uc_host); 1294601Swnj tp->t_state = LISTEN; 1304601Swnj goto badseg; 1314601Swnj 1324601Swnj default: 1334601Swnj t_close(tp, URESET); /* 66 */ 1344601Swnj tp->t_state = CLOSED; 1354601Swnj goto badseg; 1364601Swnj } 1374601Swnj /*NOTREACHED*/ 1384601Swnj 1394601Swnj case SYN_RCVD: 1404601Swnj common: 1414601Swnj if (ack_ok(tp, n) == 0) { 1424601Swnj send_rst(tp, n); /* 74 */ 1434601Swnj goto badseg; 1444601Swnj } 1454601Swnj if (syn_ok(tp, n) && n->t_seq != tp->irs) { 1464601Swnj send_null(tp); /* 74 */ 1474601Swnj goto badseg; 1484601Swnj } 1494601Swnj goto goodseg; 1504601Swnj } 1514601Swnj badseg: 1524601Swnj m_freem(mp); 1534601Swnj return; 1544601Swnj 1554601Swnj goodseg: 1564601Swnj #ifdef notdef 1574601Swnj /* 1584601Swnj * Defer processing if no buffer space for this connection. 1594601Swnj */ 1604601Swnj up = tp->t_ucb; 1614601Swnj if ((int)up->uc_rcv - (int)up->uc_rsize <= 0 1624601Swnj && n->t_len != 0 && netcb.n_bufs < netcb.n_lowat) { 1634601Swnj mp->m_act = (struct mbuf *)0; 1644601Swnj if ((m = tp->t_rcv_unack) != NULL) { 1654601Swnj while (m->m_act != NULL) 1664601Swnj m = m->m_act; 1674601Swnj m->m_act = mp; 1684601Swnj } else 1694601Swnj tp->t_rcv_unack = mp; 1704601Swnj 1714601Swnj return; 1724601Swnj } 1734601Swnj #endif 1744601Swnj 1754601Swnj /* 1764601Swnj * Discard ip header, and do tcp input processing. 1774601Swnj */ 1784601Swnj hlen += sizeof(struct ip); 1794601Swnj mp->m_off += hlen; 1804601Swnj mp->m_len -= hlen; 1814601Swnj nstate = tp->t_state; 1824601Swnj tp->tc_flags &= ~TC_NET_KEEP; 1834601Swnj acounts[tp->t_state][INRECV]++; 1844601Swnj #ifdef TCPDEBUG 1854601Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 1864601Swnj tdb.td_tod = time; 1874601Swnj tdb.td_tcb = tp; 1884601Swnj tdb.td_old = nstate; 1894601Swnj tdb.td_inp = INRECV; 1904601Swnj tdb.td_tim = 0; 1914601Swnj tdb.td_sno = n->t_seq; 1924601Swnj tdb.td_ano = n->t_ackno; 1934601Swnj tdb.td_wno = n->t_win; 1944601Swnj tdb.td_lno = n->t_len; 1954601Swnj tdb.td_flg = n->th_flags; 1964601Swnj } else 1974601Swnj tdb.td_tod = 0; 1984601Swnj #endif 1994601Swnj switch (tp->t_state) { 2004601Swnj 2014601Swnj case LISTEN: 2024601Swnj if (!syn_ok(tp, n) || 2034601Swnj ((tp->t_ucb->uc_host = h_make(&n->t_s)) == 0)) { 2044601Swnj nstate = EFAILEC; 2054601Swnj goto done; 2064601Swnj } 2074601Swnj tp->t_fport = n->t_src; 208*4603Sroot tp->t_ucb->uc_template = tcp_template(tp); 2094601Swnj rcv_ctldat(tp, n, 1); 2104601Swnj if (tp->tc_flags&TC_FIN_RCVD) { 2114601Swnj tp->t_finack = T_2ML; /* 3 */ 2124601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 2134601Swnj nstate = CLOSE_WAIT; 2144601Swnj } else { 2154601Swnj tp->t_init = T_INIT / 2; /* 4 */ 2164601Swnj nstate = L_SYN_RCVD; 2174601Swnj } 2184601Swnj goto done; 2194601Swnj 2204601Swnj case SYN_SENT: 2214601Swnj if (!syn_ok(tp, n)) { 2224601Swnj nstate = EFAILEC; 2234601Swnj goto done; 2244601Swnj } 2254601Swnj rcv_ctldat(tp, n, 1); 2264601Swnj if (tp->tc_flags&TC_FIN_RCVD) { 2274601Swnj if (n->th_flags&TH_ACK) { 2284601Swnj if (n->t_ackno > tp->iss) 2294601Swnj present_data(tp); /* 32 */ 2304601Swnj } else { 2314601Swnj tp->t_finack = T_2ML; /* 9 */ 2324601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 2334601Swnj } 2344601Swnj nstate = CLOSE_WAIT; 2354601Swnj goto done; 2364601Swnj } 2374601Swnj if (n->th_flags&TH_ACK) { 2384601Swnj present_data(tp); /* 11 */ 2394601Swnj nstate = ESTAB; 2404601Swnj } else 2414601Swnj nstate = SYN_RCVD; /* 8 */ 2424601Swnj goto done; 2434601Swnj 2444601Swnj case SYN_RCVD: 2454601Swnj case L_SYN_RCVD: 2464601Swnj if ((n->th_flags&TH_ACK) == 0 || 2474601Swnj (n->th_flags&TH_ACK) && n->t_ackno <= tp->iss) { 2484601Swnj nstate = EFAILEC; 2494601Swnj goto done; 2504601Swnj } 2514601Swnj goto input; 2524601Swnj 2534601Swnj case ESTAB: 2544601Swnj case FIN_W1: 2554601Swnj case FIN_W2: 2564601Swnj case TIME_WAIT: 2574601Swnj input: 2584601Swnj rcv_ctldat(tp, n, 1); /* 39 */ 2594601Swnj present_data(tp); 2604601Swnj switch (tp->t_state) { 2614601Swnj 2624601Swnj case ESTAB: 2634601Swnj if (tp->tc_flags&TC_FIN_RCVD) 2644601Swnj nstate = CLOSE_WAIT; 2654601Swnj break; 2664601Swnj 2674601Swnj case SYN_RCVD: 2684601Swnj case L_SYN_RCVD: 2694601Swnj nstate = (tp->tc_flags&TC_FIN_RCVD) ? 2704601Swnj CLOSE_WAIT : ESTAB; /* 33:5 */ 2714601Swnj break; 2724601Swnj 2734601Swnj case FIN_W1: 2744601Swnj j = ack_fin(tp, n); 2754601Swnj if ((tp->tc_flags & TC_FIN_RCVD) == 0) { 2764601Swnj if (j) 2774601Swnj nstate = FIN_W2; /* 27 */ 2784601Swnj break; 2794601Swnj } 2804601Swnj tp->t_finack = T_2ML; 2814601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 2824601Swnj nstate = j ? TIME_WAIT : CLOSING1; /* 28:26 */ 2834601Swnj break; 2844601Swnj 2854601Swnj case FIN_W2: 2864601Swnj if (tp->tc_flags&TC_FIN_RCVD) { 2874601Swnj tp->t_finack = T_2ML; /* 29 */ 2884601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 2894601Swnj nstate = TIME_WAIT; 2904601Swnj break; 2914601Swnj } 2924601Swnj break; 2934601Swnj } 2944601Swnj goto done; 2954601Swnj 2964601Swnj case CLOSE_WAIT: 2974601Swnj if (n->th_flags&TH_FIN) { 2984601Swnj if ((n->th_flags&TH_ACK) && 2994601Swnj n->t_ackno <= tp->seq_fin) { 3004601Swnj rcv_ctldat(tp, n, 0); /* 30 */ 3014601Swnj tp->t_finack = T_2ML; 3024601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 3034601Swnj } else 3044601Swnj send_ctl(tp); /* 31 */ 3054601Swnj goto done; 3064601Swnj } 3074601Swnj goto input; 3084601Swnj 3094601Swnj case CLOSING1: 3104601Swnj j = ack_fin(tp, n); 3114601Swnj if (n->th_flags&TH_FIN) { 3124601Swnj rcv_ctldat(tp, n, 0); 3134601Swnj tp->t_finack = T_2ML; 3144601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 3154601Swnj if (j) 3164601Swnj nstate = TIME_WAIT; /* 23 */ 3174601Swnj goto done; 3184601Swnj } 3194601Swnj if (j) { 3204601Swnj if (tp->tc_flags&TC_WAITED_2_ML) 3214601Swnj if (rcv_empty(tp)) { 3224601Swnj t_close(tp, UCLOSED); /* 15 */ 3234601Swnj nstate = CLOSED; 3244601Swnj } else 3254601Swnj nstate = RCV_WAIT; /* 18 */ 3264601Swnj else 3274601Swnj nstate = TIME_WAIT; 3284601Swnj goto done; 3294601Swnj } 3304601Swnj goto input; 3314601Swnj 3324601Swnj case CLOSING2: 3334601Swnj if (ack_fin(tp, n)) { 3344601Swnj if (rcv_empty(tp)) { /* 16 */ 3354601Swnj t_close(tp, UCLOSED); 3364601Swnj nstate = CLOSED; 3374601Swnj } else 3384601Swnj nstate = RCV_WAIT; /* 19 */ 3394601Swnj goto done; 3404601Swnj } 3414601Swnj if (n->th_flags&TH_FIN) { 3424601Swnj send_ctl(tp); /* 31 */ 3434601Swnj goto done; 3444601Swnj } 3454601Swnj goto input; 3464601Swnj 3474601Swnj case RCV_WAIT: 3484601Swnj if ((n->th_flags&TH_FIN) && (n->th_flags&TH_ACK) && 3494601Swnj n->t_ackno <= tp->seq_fin) { 3504601Swnj rcv_ctldat(tp, n, 0); 3514601Swnj tp->t_finack = T_2ML; 3524601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; /* 30 */ 3534601Swnj } 3544601Swnj goto done; 3554601Swnj } 3564601Swnj panic("tcp_input"); 3574601Swnj done: 3584601Swnj 3594601Swnj /* 3604601Swnj * Done with state*input specific processing. 3614601Swnj * Form trace records, free input if not needed, 3624601Swnj * and enter new state. 3634601Swnj */ 3644601Swnj #ifdef TCPDEBUG 3654601Swnj if (tdb.td_tod) { 3664601Swnj tdb.td_new = nstate; 3674601Swnj tcp_debug[tdbx++ % TDBSIZE] = tdb; 3684601Swnj if (tcpconsdebug) 3694601Swnj tcp_prt(&tdb); 3704601Swnj } 3714601Swnj #endif 3724601Swnj switch (nstate) { 3734601Swnj 3744601Swnj case EFAILEC: 3754601Swnj m_freem(mp); 3764601Swnj return; 3774601Swnj 3784601Swnj default: 3794601Swnj tp->t_state = nstate; 3804601Swnj /* fall into ... */ 3814601Swnj 3824601Swnj case CLOSED: 3834601Swnj /* IF CLOSED CANT LOOK AT tc_flags */ 3844601Swnj if ((tp->tc_flags&TC_NET_KEEP) == 0) 3854601Swnj m_freem(mp); 3864601Swnj return; 3874601Swnj } 3884601Swnj /* NOTREACHED */ 3894601Swnj 3904601Swnj /* 3914601Swnj * Unwanted packed; free everything 3924601Swnj * but the header and return an rst. 3934601Swnj */ 3944601Swnj notwanted: 3954601Swnj m_freem(mp->m_next); 3964601Swnj mp->m_next = NULL; 3974601Swnj mp->m_len = sizeof(struct th); 3984601Swnj #define xchg(a,b) j=a; a=b; b=j 3994601Swnj xchg(n->t_d.s_addr, n->t_s.s_addr); xchg(n->t_dst, n->t_src); 4004601Swnj #undef xchg 4014601Swnj if (n->th_flags&TH_ACK) 4024601Swnj n->t_seq = n->t_ackno; 4034601Swnj else { 4044601Swnj n->t_ackno = htonl(ntohl(n->t_seq) + tlen - hlen); 4054601Swnj n->t_seq = 0; 4064601Swnj } 4074601Swnj n->th_flags = TH_RST; /* not TH_FIN, TH_SYN */ 4084601Swnj n->th_flags ^= TH_ACK; 4094601Swnj n->t_len = htons(TCPSIZE); 4104601Swnj n->t_off = 5; 4114601Swnj n->t_sum = cksum(mp, sizeof(struct th)); 4124601Swnj ((struct ip *)n)->ip_len = sizeof(struct th); 4134601Swnj ip_output(mp); 4144601Swnj netstat.t_badsegs++; 4154601Swnj } 4164601Swnj 4174601Swnj rcv_ctldat(tp, n, dataok) 4184601Swnj register struct tcb *tp; 4194601Swnj register struct th *n; 4204601Swnj { 4214601Swnj register sent; 4224601Swnj register struct ucb *up; 4234601Swnj register struct mbuf *m, *mn; 4244601Swnj register len; 4254601Swnj COUNT(RCV_CTLDAT); 4264601Swnj 4274601Swnj tp->tc_flags &= ~(TC_DROPPED_TXT|TC_ACK_DUE|TC_NEW_WINDOW); 4284601Swnj /* syn */ 4294601Swnj if ((tp->tc_flags&TC_SYN_RCVD) == 0 && (n->th_flags&TH_SYN)) { 4304601Swnj tp->irs = n->t_seq; 4314601Swnj tp->rcv_nxt = n->t_seq + 1; 4324601Swnj tp->snd_wl = tp->rcv_urp = tp->irs; 4334601Swnj tp->tc_flags |= (TC_SYN_RCVD|TC_ACK_DUE); 4344601Swnj } 4354601Swnj /* ack */ 4364601Swnj if ((n->th_flags&TH_ACK) && (tp->tc_flags&TC_SYN_RCVD) && 4374601Swnj n->t_ackno > tp->snd_una) { 4384601Swnj up = tp->t_ucb; 4394601Swnj 4404601Swnj /* update snd_una and snd_nxt */ 4414601Swnj tp->snd_una = n->t_ackno; 4424601Swnj if (tp->snd_una > tp->snd_nxt) 4434601Swnj tp->snd_nxt = tp->snd_una; 4444601Swnj 4454601Swnj /* if timed msg acked, set retrans time value */ 4464601Swnj if ((tp->tc_flags&TC_SYN_ACKED) && 4474601Swnj tp->snd_una > tp->t_xmt_val) { 4484601Swnj tp->t_xmtime = (tp->t_xmt != 0 ? tp->t_xmt : T_REXMT); 4494601Swnj if (tp->t_xmtime > T_REMAX) 4504601Swnj tp->t_xmtime = T_REMAX; 4514601Swnj } 4524601Swnj 4534601Swnj /* remove acked data from send buf */ 4544601Swnj len = tp->snd_una - tp->snd_off; 4554601Swnj m = up->uc_sbuf; 4564601Swnj while (len > 0 && m != NULL) 4574601Swnj if (m->m_len <= len) { 4584601Swnj len -= m->m_len; 4594601Swnj if (m->m_off > MMAXOFF) 4604601Swnj up->uc_ssize -= NMBPG; 4614601Swnj MFREE(m, mn); 4624601Swnj m = mn; 4634601Swnj up->uc_ssize--; 4644601Swnj } else { 4654601Swnj m->m_len -= len; 4664601Swnj m->m_off += len; 4674601Swnj break; 4684601Swnj } 4694601Swnj up->uc_sbuf = m; 4704601Swnj tp->snd_off = tp->snd_una; 4714601Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0 && 4724601Swnj (tp->snd_una > tp->iss)) { 4734601Swnj tp->tc_flags |= TC_SYN_ACKED; 4744601Swnj tp->t_init = 0; 4754601Swnj } 4764601Swnj if (tp->seq_fin != tp->iss && tp->snd_una > tp->seq_fin) 4774601Swnj tp->tc_flags &= ~TC_SND_FIN; 4784601Swnj tp->t_rexmt = 0; 4794601Swnj tp->t_rexmttl = 0; 4804601Swnj tp->tc_flags |= TC_CANCELLED; 4814601Swnj netwakeup(tp->t_ucb); /* wasteful */ 4824601Swnj } 4834601Swnj /* win */ 4844601Swnj if ((tp->tc_flags & TC_SYN_RCVD) && n->t_seq >= tp->snd_wl) { 4854601Swnj tp->snd_wl = n->t_seq; 4864601Swnj tp->snd_wnd = n->t_win; 4874601Swnj tp->tc_flags |= TC_NEW_WINDOW; 4884601Swnj tp->t_persist = 0; 4894601Swnj } 4904601Swnj if (dataok) { 4914601Swnj /* text */ 4924601Swnj if (n->t_len != 0) 4934601Swnj rcv_text(tp, n); 4944601Swnj /* urg */ 4954601Swnj if (n->th_flags&TH_URG) { 4964601Swnj unsigned urgent; 4974601Swnj 4984601Swnj urgent = n->t_urp + n->t_seq; 4994601Swnj if (tp->rcv_nxt < urgent) { 5004601Swnj if (tp->rcv_urp <= tp->rcv_nxt) 5014601Swnj to_user(tp->t_ucb, UURGENT); 5024601Swnj tp->rcv_urp = urgent; 5034601Swnj } 5044601Swnj } 5054601Swnj /* eol */ 5064601Swnj if ((n->th_flags&TH_EOL) && 5074601Swnj (tp->tc_flags&TC_DROPPED_TXT) == 0 && 5084601Swnj tp->t_rcv_prev != (struct th *)tp) { 5094601Swnj /* mark last mbuf */ 5104601Swnj m = dtom(tp->t_rcv_prev); 5114601Swnj if (m != NULL) { 5124601Swnj while (m->m_next != NULL) 5134601Swnj m = m->m_next; 5144601Swnj m->m_act = 5154601Swnj (struct mbuf *)(m->m_off + m->m_len - 1); 5164601Swnj } 5174601Swnj } 5184601Swnj } 5194601Swnj /* fin */ 5204601Swnj if ((n->th_flags&TH_FIN) && (tp->tc_flags&TC_DROPPED_TXT) == 0) { 5214601Swnj int last; 5224601Swnj 5234601Swnj if ((tp->tc_flags&TC_FIN_RCVD) == 0) { 5244601Swnj /* do we really have fin ? */ 5254601Swnj last = firstempty(tp); 5264601Swnj if (tp->t_rcv_prev == (struct th *)tp || 5274601Swnj last == t_end(tp->t_rcv_prev)) { 5284601Swnj tp->tc_flags |= TC_FIN_RCVD; 5294601Swnj netwakeup(tp->t_ucb); /* poke */ 5304601Swnj } 5314601Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 5324601Swnj tp->rcv_nxt >= last) { 5334601Swnj tp->rcv_nxt = last + 1; /* fin seq */ 5344601Swnj tp->tc_flags |= TC_ACK_DUE; 5354601Swnj } 5364601Swnj } else 5374601Swnj tp->tc_flags |= TC_ACK_DUE; 5384601Swnj } 5394601Swnj 5404601Swnj /* respond */ 5414601Swnj if (tp->tc_flags&TC_ACK_DUE) 5424601Swnj sent = send_ctl(tp); 5434601Swnj else if (tp->tc_flags&TC_NEW_WINDOW) 5444601Swnj sent = send(tp); 5454601Swnj else 5464601Swnj sent = 0; 5474601Swnj 5484601Swnj /* set for retrans */ 5494601Swnj if (!sent && tp->snd_una < tp->snd_nxt && 5504601Swnj (tp->tc_flags&TC_CANCELLED)) { 5514601Swnj tp->t_rexmt = tp->t_xmtime; 5524601Swnj tp->t_rexmttl = T_REXMTTL; 5534601Swnj tp->t_rexmt_val = tp->t_rtl_val = tp->snd_lst; 5544601Swnj tp->tc_flags &= ~TC_CANCELLED; 5554601Swnj } 5564601Swnj } 5574601Swnj 5584601Swnj rcv_text(tp, t) 5594601Swnj register struct tcb *tp; 5604601Swnj register struct th *t; 5614601Swnj { 5624601Swnj register i; 5634601Swnj register struct th *p, *q; 5644601Swnj register struct mbuf *m, *n; 5654601Swnj struct th *savq; 5664601Swnj int last, j, k; 5674601Swnj COUNT(RCV_TEXT); 5684601Swnj 5694601Swnj /* throw away any data we have already received */ 5704601Swnj if ((i = tp->rcv_nxt - t->t_seq) > 0) { 5714601Swnj if (i >= t->t_len) 5724601Swnj return; 5734601Swnj t->t_seq += i; 5744601Swnj t->t_len -= i; 5754601Swnj m_adj(dtom(t), i); 5764601Swnj } 5774601Swnj 5784601Swnj last = t_end(t); /* last seq # in incoming seg */ 5794601Swnj i = rcv_resource(tp); /* # buffers available to con */ 5804601Swnj 5814601Swnj /* count buffers in segment */ 5824601Swnj 5834601Swnj for (m = dtom(t), j = 0; m != NULL; m = m->m_next) 5844601Swnj if (m->m_len != 0) { 5854601Swnj j++; 5864601Swnj if (m->m_off > MMAXOFF) 5874601Swnj j += NMBPG; 5884601Swnj } 5894601Swnj 5904601Swnj /* not enough resources to process segment */ 5914601Swnj 5924601Swnj if (j > i && netcb.n_bufs < netcb.n_lowat) { 5934601Swnj 5944601Swnj /* if segment preceeds top of seqeuncing queue, try to take 5954601Swnj buffers from bottom of queue */ 5964601Swnj 5974601Swnj q = tp->t_rcv_next; 5984601Swnj if (q != (struct th *)tp && tp->rcv_nxt < q->t_seq && 5994601Swnj t->t_seq < q->t_seq) 6004601Swnj 6014601Swnj for (k=j-i, p = tp->t_rcv_prev; k > 0 && 6024601Swnj p != (struct th *)tp; k--) { 6034601Swnj savq = p->t_prev; 6044601Swnj tcp_deq(p); 6054601Swnj i += m_freem(dtom(p)); 6064601Swnj p = savq; 6074601Swnj } 6084601Swnj 6094601Swnj /* if still not enough room, drop text from end of segment */ 6104601Swnj 6114601Swnj if (j > i) { 6124601Swnj 6134601Swnj for (m = dtom(t); i > 0 && m != NULL; i--) 6144601Swnj m = m->m_next; 6154601Swnj 6164601Swnj while (m != NULL) { 6174601Swnj t->t_len -= m->m_len; 6184601Swnj last -= m->m_len; 6194601Swnj m->m_len = 0; 6204601Swnj m = m->m_next; 6214601Swnj } 6224601Swnj tp->tc_flags |= TC_DROPPED_TXT; 6234601Swnj if (last < t->t_seq) 6244601Swnj return; 6254601Swnj } 6264601Swnj } 6274601Swnj 6284601Swnj /* merge incoming data into the sequence queue */ 6294601Swnj 6304601Swnj q = tp->t_rcv_next; /* -> top of sequencing queue */ 6314601Swnj 6324601Swnj /* skip frags which new doesn't overlap at end */ 6334601Swnj 6344601Swnj while ((q != (struct th *)tp) && (t->t_seq > t_end(q))) 6354601Swnj q = q->t_next; 6364601Swnj 6374601Swnj if (q == (struct th *)tp) { /* frag at end of chain */ 6384601Swnj 6394601Swnj if (last >= tp->rcv_nxt) { 6404601Swnj tp->tc_flags |= TC_NET_KEEP; 6414601Swnj tcp_enq(t, tp->t_rcv_prev); 6424601Swnj } 6434601Swnj 6444601Swnj } else { 6454601Swnj 6464601Swnj /* frag doesn't overlap any on chain */ 6474601Swnj 6484601Swnj if (last < q->t_seq) { 6494601Swnj tp->tc_flags |= TC_NET_KEEP; 6504601Swnj tcp_enq(t, q->t_prev); 6514601Swnj 6524601Swnj /* new overlaps beginning of next frag only */ 6534601Swnj 6544601Swnj } else if (last < t_end(q)) { 6554601Swnj if ((i = last - q->t_seq + 1) < t->t_len) { 6564601Swnj t->t_len -= i; 6574601Swnj m_adj(dtom(t), -i); 6584601Swnj tp->tc_flags |= TC_NET_KEEP; 6594601Swnj tcp_enq(t, q->t_prev); 6604601Swnj } 6614601Swnj 6624601Swnj /* new overlaps end of previous frag */ 6634601Swnj 6644601Swnj } else { 6654601Swnj savq = q; 6664601Swnj if (t->t_seq <= q->t_seq) { /* complete cover */ 6674601Swnj savq = q->t_prev; 6684601Swnj tcp_deq(q); 6694601Swnj m_freem(dtom(q)); 6704601Swnj 6714601Swnj } else { /* overlap */ 6724601Swnj if ((i = t_end(q) - t->t_seq + 1) < t->t_len) { 6734601Swnj t->t_seq += i; 6744601Swnj t->t_len -= i; 6754601Swnj m_adj(dtom(t), i); 6764601Swnj } else 6774601Swnj t->t_len = 0; 6784601Swnj } 6794601Swnj 6804601Swnj /* new overlaps at beginning of successor frags */ 6814601Swnj 6824601Swnj q = savq->t_next; 6834601Swnj while ((q != (struct th *)tp) && (t->t_len != 0) && 6844601Swnj (q->t_seq < last)) 6854601Swnj 6864601Swnj /* complete cover */ 6874601Swnj 6884601Swnj if (t_end(q) <= last) { 6894601Swnj p = q->t_next; 6904601Swnj tcp_deq(q); 6914601Swnj m_freem(dtom(q)); 6924601Swnj q = p; 6934601Swnj 6944601Swnj } else { /* overlap */ 6954601Swnj 6964601Swnj if ((i = last - q->t_seq + 1) < t->t_len) { 6974601Swnj t->t_len -= i; 6984601Swnj m_adj(dtom(t), -i); 6994601Swnj } else 7004601Swnj t->t_len = 0; 7014601Swnj break; 7024601Swnj } 7034601Swnj 7044601Swnj /* enqueue whatever is left of new before successors */ 7054601Swnj 7064601Swnj if (t->t_len != 0) { 7074601Swnj tp->tc_flags |= TC_NET_KEEP; 7084601Swnj tcp_enq(t, savq); 7094601Swnj } 7104601Swnj } 7114601Swnj } 7124601Swnj 7134601Swnj /* set to ack completed data (no gaps) */ 7144601Swnj 7154601Swnj tp->rcv_nxt = firstempty(tp); 7164601Swnj tp->tc_flags |= TC_ACK_DUE; 7174601Swnj 7184601Swnj #ifdef notdef 7194601Swnj /* THIS CODE CANT POSSIBLY WORK */ 7204601Swnj /* if any room remaining in rcv buf, take any unprocessed 7214601Swnj messages and schedule for later processing */ 7224601Swnj 7234601Swnj i = rcv_resource(tp); 7244601Swnj 7254601Swnj while ((m = tp->t_rcv_unack) != NULL && i > 0) { 7264601Swnj 7274601Swnj /* schedule work request */ 7284601Swnj 7294601Swnj t = (struct th *)((int)m + m->m_off); 7304601Swnj j = (t->t_off << 2) + sizeof(struct ip); 7314601Swnj m->m_off += j; 7324601Swnj m->m_len -= j; 7334601Swnj tp->t_rcv_unack = m->m_act; 7344601Swnj m->m_act = (struct mbuf *)0; 7354601Swnj netstat.t_unack++; 7364601Swnj tcp_work(INRECV, 0, tp, t); 7374601Swnj 7384601Swnj /* remaining buffer space */ 7394601Swnj 7404601Swnj for (n = m; n != NULL; n = n->m_next) 7414601Swnj i--; 7424601Swnj } 7434601Swnj #endif 7444601Swnj } 7454601Swnj 7464601Swnj present_data(tp) 7474601Swnj register struct tcb *tp; 7484601Swnj { 7494601Swnj register struct th *t; 7504601Swnj register struct ucb *up; 7514601Swnj register struct mbuf *m, **mp; 7524601Swnj seq_t ready; 7534601Swnj COUNT(PRESENT_DATA); 7544601Swnj 7554601Swnj /* connection must be synced and data available for user */ 7564601Swnj if (((tp->tc_flags&TC_SYN_ACKED) == 0) || 7574601Swnj (t = tp->t_rcv_next) == (struct th *)tp) 7584601Swnj return; 7594601Swnj up = tp->t_ucb; 7604601Swnj ready = firstempty(tp); /* seq # of last complete datum */ 7614601Swnj mp = &up->uc_rbuf; 7624601Swnj while (*mp) 7634601Swnj mp = &(*mp)->m_next; 7644601Swnj while (up->uc_rsize < up->uc_rcv && t != (struct th *) tp && 7654601Swnj t_end(t) < ready) { 7664601Swnj tcp_deq(t); 7674601Swnj m = dtom(t); 7684601Swnj t = t->t_next; 7694601Swnj while (m) { 7704601Swnj if (m->m_len == 0) { 7714601Swnj m = m_free(m); 7724601Swnj continue; 7734601Swnj } 7744601Swnj up->uc_rsize++; 7754601Swnj if (m->m_off > MMAXOFF) 7764601Swnj up->uc_rsize += NMBPG; 7774601Swnj if (*mp == 0) 7784601Swnj *mp = m; 7794601Swnj mp = &m->m_next; 7804601Swnj m = *mp; 7814601Swnj } 7824601Swnj } 7834601Swnj if (up->uc_rsize != 0) 7844601Swnj netwakeup(up); 7854601Swnj /* 7864601Swnj * Let user know about foreign tcp close if no more data. 7874601Swnj */ 7884601Swnj if ((tp->tc_flags&TC_FIN_RCVD) && (tp->tc_flags&TC_USR_CLOSED) == 0 && 7894601Swnj rcv_empty(tp)) 7904601Swnj to_user(up, UCLOSED); 7914601Swnj } 792