1*4671Swnj /* tcp_input.c 1.8 81/10/30 */ 24601Swnj 34601Swnj #include "../h/param.h" 44601Swnj #include "../h/systm.h" 54663Swnj #include "../h/mbuf.h" 64663Swnj #include "../h/socket.h" 74663Swnj #include "../inet/inet.h" 84663Swnj #include "../inet/inet_systm.h" 94663Swnj #include "../inet/imp.h" 104663Swnj #include "../inet/inet_host.h" 114663Swnj #include "../inet/ip.h" 124663Swnj #include "../inet/tcp.h" 134663Swnj #include "../inet/tcp_fsm.h" 144601Swnj 154601Swnj extern int nosum; 164601Swnj 174601Swnj tcp_input(mp) 184601Swnj register struct mbuf *mp; 194601Swnj { 204601Swnj register struct tcb *tp; 214601Swnj register struct th *n; 224601Swnj int nstate; 234601Swnj struct mbuf *m; 244601Swnj struct ucb *up; 254601Swnj int hlen, tlen, j; 264601Swnj u_short lport, fport; 274601Swnj #ifdef TCPDEBUG 284601Swnj struct tcp_debug tdb; 294601Swnj #endif 304601Swnj COUNT(TCP_INPUT); 314601Swnj 324601Swnj /* 334601Swnj * Build extended tcp header 344601Swnj */ 354601Swnj n = (struct th *)((int)mp + mp->m_off); 364601Swnj tlen = ((struct ip *)n)->ip_len; 374601Swnj n->t_len = htons(tlen); 384601Swnj n->t_next = NULL; 394601Swnj n->t_prev = NULL; 404601Swnj n->t_x1 = 0; 414601Swnj lport = ntohs(n->t_dst); 424601Swnj fport = ntohs(n->t_src); 434601Swnj 444601Swnj /* WONT BE POSSIBLE WHEN MBUFS ARE 256 BYTES */ 454601Swnj if ((hlen = n->t_off << 2) > mp->m_len) 464601Swnj { printf("tcp header overflow\n"); m_freem(mp); return; } 474601Swnj 484601Swnj /* 494601Swnj * Checksum extended header and data 504601Swnj */ 514601Swnj j = n->t_sum; n->t_sum = 0; 524601Swnj if (j != cksum(mp, sizeof (struct ip) + tlen)) { 534601Swnj netstat.t_badsum++; 544601Swnj if (nosum == 0) { 554601Swnj m_freem(mp); 564601Swnj return; 574601Swnj } 584601Swnj } 594601Swnj 604601Swnj /* 614601Swnj * Find tcb for message (SHOULDN'T USE LINEAR SEARCH!) 624601Swnj */ 634663Swnj for (tp = tcb_head; tp != 0; tp = tp->t_tcb_next) 644601Swnj if (tp->t_lport == lport && tp->t_fport == fport && 654601Swnj tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr) 664601Swnj goto found; 674663Swnj for (tp = tcb_head; tp != 0; tp = tp->t_tcb_next) 684601Swnj if (tp->t_lport == lport && 694601Swnj (tp->t_fport==fport || tp->t_fport==0) && 704601Swnj (tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr || 714601Swnj tp->t_ucb->uc_host->h_addr.s_addr == 0)) 724601Swnj goto found; 734601Swnj goto notwanted; 744601Swnj found: 754601Swnj 764601Swnj /* 774601Swnj * Byte swap header 784601Swnj */ 794601Swnj n->t_len = tlen - hlen; 804601Swnj n->t_src = fport; 814601Swnj n->t_dst = lport; 824601Swnj n->t_seq = ntohl(n->t_seq); 834601Swnj n->t_ackno = ntohl(n->t_ackno); 844601Swnj n->t_win = ntohs(n->t_win); 854601Swnj n->t_urp = ntohs(n->t_urp); 864601Swnj 874601Swnj /* 884601Swnj * Check segment seq # and do rst processing 894601Swnj */ 904601Swnj switch (tp->t_state) { 914601Swnj 924601Swnj case LISTEN: 934601Swnj if ((n->th_flags&TH_ACK) || !syn_ok(tp, n)) { 944601Swnj send_rst(tp, n); 954601Swnj goto badseg; 964601Swnj } 974601Swnj if (n->th_flags&TH_RST) 984601Swnj goto badseg; 994601Swnj goto goodseg; 1004601Swnj 1014601Swnj case SYN_SENT: 1024601Swnj if (!ack_ok(tp, n) || !syn_ok(tp, n)) { 1034601Swnj send_rst(tp, n); /* 71,72,75 */ 1044601Swnj goto badseg; 1054601Swnj } 1064601Swnj if (n->th_flags&TH_RST) { 1074601Swnj t_close(tp, URESET); /* 70 */ 1084601Swnj tp->t_state = CLOSED; 1094601Swnj goto badseg; 1104601Swnj } 1114601Swnj goto goodseg; 1124601Swnj 1134601Swnj default: 1144601Swnj if ((n->th_flags&TH_RST) == 0) 1154601Swnj goto common; 1164601Swnj if (n->t_seq < tp->rcv_nxt) /* bad rst */ 1174601Swnj goto badseg; /* 69 */ 1184601Swnj switch (tp->t_state) { 1194601Swnj 1204601Swnj case L_SYN_RCVD: 1214601Swnj if (ack_ok(tp, n) == 0) 1224601Swnj goto badseg; /* 69 */ 1234601Swnj tp->t_rexmt = 0; 1244601Swnj tp->t_rexmttl = 0; 1254601Swnj tp->t_persist = 0; 1264601Swnj h_free(tp->t_ucb->uc_host); 1274601Swnj tp->t_state = LISTEN; 1284601Swnj goto badseg; 1294601Swnj 1304601Swnj default: 1314601Swnj t_close(tp, URESET); /* 66 */ 1324601Swnj tp->t_state = CLOSED; 1334601Swnj goto badseg; 1344601Swnj } 1354601Swnj /*NOTREACHED*/ 1364601Swnj 1374601Swnj case SYN_RCVD: 1384601Swnj common: 1394601Swnj if (ack_ok(tp, n) == 0) { 1404601Swnj send_rst(tp, n); /* 74 */ 1414601Swnj goto badseg; 1424601Swnj } 1434601Swnj if (syn_ok(tp, n) && n->t_seq != tp->irs) { 1444601Swnj send_null(tp); /* 74 */ 1454601Swnj goto badseg; 1464601Swnj } 1474601Swnj goto goodseg; 1484601Swnj } 1494601Swnj badseg: 1504601Swnj m_freem(mp); 1514601Swnj return; 1524601Swnj 1534601Swnj goodseg: 1544601Swnj #ifdef notdef 1554601Swnj /* 1564601Swnj * Defer processing if no buffer space for this connection. 1574601Swnj */ 1584601Swnj up = tp->t_ucb; 1594656Swnj if (up->uc_rcc > up->uc_rhiwat && 1604663Swnj && n->t_len != 0 && mbstat.m_bufs < mbstat.m_lowat) { 1614601Swnj mp->m_act = (struct mbuf *)0; 1624601Swnj if ((m = tp->t_rcv_unack) != NULL) { 1634601Swnj while (m->m_act != NULL) 1644601Swnj m = m->m_act; 1654601Swnj m->m_act = mp; 1664601Swnj } else 1674601Swnj tp->t_rcv_unack = mp; 1684601Swnj return; 1694601Swnj } 1704601Swnj #endif 1714601Swnj 1724601Swnj /* 1734601Swnj * Discard ip header, and do tcp input processing. 1744601Swnj */ 1754601Swnj hlen += sizeof(struct ip); 1764601Swnj mp->m_off += hlen; 1774601Swnj mp->m_len -= hlen; 1784601Swnj nstate = tp->t_state; 1794601Swnj tp->tc_flags &= ~TC_NET_KEEP; 1804601Swnj acounts[tp->t_state][INRECV]++; 1814601Swnj #ifdef TCPDEBUG 1824601Swnj if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 1834604Swnj tdb_setup(tp, n, INRECV, &tdb); 1844601Swnj } else 1854601Swnj tdb.td_tod = 0; 1864601Swnj #endif 1874601Swnj switch (tp->t_state) { 1884601Swnj 1894601Swnj case LISTEN: 1904601Swnj if (!syn_ok(tp, n) || 1914601Swnj ((tp->t_ucb->uc_host = h_make(&n->t_s)) == 0)) { 1924601Swnj nstate = EFAILEC; 1934601Swnj goto done; 1944601Swnj } 1954601Swnj tp->t_fport = n->t_src; 1964603Sroot tp->t_ucb->uc_template = tcp_template(tp); 1974601Swnj rcv_ctldat(tp, n, 1); 1984601Swnj if (tp->tc_flags&TC_FIN_RCVD) { 1994601Swnj tp->t_finack = T_2ML; /* 3 */ 2004601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 2014601Swnj nstate = CLOSE_WAIT; 2024601Swnj } else { 2034601Swnj tp->t_init = T_INIT / 2; /* 4 */ 2044601Swnj nstate = L_SYN_RCVD; 2054601Swnj } 2064601Swnj goto done; 2074601Swnj 2084601Swnj case SYN_SENT: 2094601Swnj if (!syn_ok(tp, n)) { 2104601Swnj nstate = EFAILEC; 2114601Swnj goto done; 2124601Swnj } 2134601Swnj rcv_ctldat(tp, n, 1); 2144601Swnj if (tp->tc_flags&TC_FIN_RCVD) { 2154601Swnj if (n->th_flags&TH_ACK) { 2164601Swnj if (n->t_ackno > tp->iss) 2174601Swnj present_data(tp); /* 32 */ 2184601Swnj } else { 2194601Swnj tp->t_finack = T_2ML; /* 9 */ 2204601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 2214601Swnj } 2224601Swnj nstate = CLOSE_WAIT; 2234601Swnj goto done; 2244601Swnj } 2254601Swnj if (n->th_flags&TH_ACK) { 2264601Swnj present_data(tp); /* 11 */ 2274601Swnj nstate = ESTAB; 2284601Swnj } else 2294601Swnj nstate = SYN_RCVD; /* 8 */ 2304601Swnj goto done; 2314601Swnj 2324601Swnj case SYN_RCVD: 2334601Swnj case L_SYN_RCVD: 2344601Swnj if ((n->th_flags&TH_ACK) == 0 || 2354601Swnj (n->th_flags&TH_ACK) && n->t_ackno <= tp->iss) { 2364601Swnj nstate = EFAILEC; 2374601Swnj goto done; 2384601Swnj } 2394601Swnj goto input; 2404601Swnj 2414601Swnj case ESTAB: 2424601Swnj case FIN_W1: 2434601Swnj case FIN_W2: 2444601Swnj case TIME_WAIT: 2454601Swnj input: 2464601Swnj rcv_ctldat(tp, n, 1); /* 39 */ 2474601Swnj present_data(tp); 2484601Swnj switch (tp->t_state) { 2494601Swnj 2504601Swnj case ESTAB: 2514601Swnj if (tp->tc_flags&TC_FIN_RCVD) 2524601Swnj nstate = CLOSE_WAIT; 2534601Swnj break; 2544601Swnj 2554601Swnj case SYN_RCVD: 2564601Swnj case L_SYN_RCVD: 2574601Swnj nstate = (tp->tc_flags&TC_FIN_RCVD) ? 2584601Swnj CLOSE_WAIT : ESTAB; /* 33:5 */ 2594601Swnj break; 2604601Swnj 2614601Swnj case FIN_W1: 2624601Swnj j = ack_fin(tp, n); 2634601Swnj if ((tp->tc_flags & TC_FIN_RCVD) == 0) { 2644601Swnj if (j) 2654601Swnj nstate = FIN_W2; /* 27 */ 2664601Swnj break; 2674601Swnj } 2684601Swnj tp->t_finack = T_2ML; 2694601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 2704601Swnj nstate = j ? TIME_WAIT : CLOSING1; /* 28:26 */ 2714601Swnj break; 2724601Swnj 2734601Swnj case FIN_W2: 2744601Swnj if (tp->tc_flags&TC_FIN_RCVD) { 2754601Swnj tp->t_finack = T_2ML; /* 29 */ 2764601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 2774601Swnj nstate = TIME_WAIT; 2784601Swnj break; 2794601Swnj } 2804601Swnj break; 2814601Swnj } 2824601Swnj goto done; 2834601Swnj 2844601Swnj case CLOSE_WAIT: 2854601Swnj if (n->th_flags&TH_FIN) { 2864601Swnj if ((n->th_flags&TH_ACK) && 2874601Swnj n->t_ackno <= tp->seq_fin) { 2884601Swnj rcv_ctldat(tp, n, 0); /* 30 */ 2894601Swnj tp->t_finack = T_2ML; 2904601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 2914601Swnj } else 2924601Swnj send_ctl(tp); /* 31 */ 2934601Swnj goto done; 2944601Swnj } 2954601Swnj goto input; 2964601Swnj 2974601Swnj case CLOSING1: 2984601Swnj j = ack_fin(tp, n); 2994601Swnj if (n->th_flags&TH_FIN) { 3004601Swnj rcv_ctldat(tp, n, 0); 3014601Swnj tp->t_finack = T_2ML; 3024601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; 3034601Swnj if (j) 3044601Swnj nstate = TIME_WAIT; /* 23 */ 3054601Swnj goto done; 3064601Swnj } 3074601Swnj if (j) { 3084601Swnj if (tp->tc_flags&TC_WAITED_2_ML) 3094601Swnj if (rcv_empty(tp)) { 3104601Swnj t_close(tp, UCLOSED); /* 15 */ 3114601Swnj nstate = CLOSED; 3124601Swnj } else 3134601Swnj nstate = RCV_WAIT; /* 18 */ 3144601Swnj else 3154601Swnj nstate = TIME_WAIT; 3164601Swnj goto done; 3174601Swnj } 3184601Swnj goto input; 3194601Swnj 3204601Swnj case CLOSING2: 3214601Swnj if (ack_fin(tp, n)) { 3224601Swnj if (rcv_empty(tp)) { /* 16 */ 3234601Swnj t_close(tp, UCLOSED); 3244601Swnj nstate = CLOSED; 3254601Swnj } else 3264601Swnj nstate = RCV_WAIT; /* 19 */ 3274601Swnj goto done; 3284601Swnj } 3294601Swnj if (n->th_flags&TH_FIN) { 3304601Swnj send_ctl(tp); /* 31 */ 3314601Swnj goto done; 3324601Swnj } 3334601Swnj goto input; 3344601Swnj 3354601Swnj case RCV_WAIT: 3364601Swnj if ((n->th_flags&TH_FIN) && (n->th_flags&TH_ACK) && 3374601Swnj n->t_ackno <= tp->seq_fin) { 3384601Swnj rcv_ctldat(tp, n, 0); 3394601Swnj tp->t_finack = T_2ML; 3404601Swnj tp->tc_flags &= ~TC_WAITED_2_ML; /* 30 */ 3414601Swnj } 3424601Swnj goto done; 3434601Swnj } 3444601Swnj panic("tcp_input"); 3454601Swnj done: 3464601Swnj 3474601Swnj /* 3484601Swnj * Done with state*input specific processing. 3494601Swnj * Form trace records, free input if not needed, 3504601Swnj * and enter new state. 3514601Swnj */ 3524601Swnj #ifdef TCPDEBUG 3534604Swnj if (tdb.td_tod) 3544604Swnj tdb_stuff(&tdb, nstate); 3554601Swnj #endif 3564601Swnj switch (nstate) { 3574601Swnj 3584601Swnj case EFAILEC: 3594601Swnj m_freem(mp); 3604601Swnj return; 3614601Swnj 3624601Swnj default: 3634601Swnj tp->t_state = nstate; 3644601Swnj /* fall into ... */ 3654601Swnj 3664601Swnj case CLOSED: 3674601Swnj /* IF CLOSED CANT LOOK AT tc_flags */ 3684601Swnj if ((tp->tc_flags&TC_NET_KEEP) == 0) 3694601Swnj m_freem(mp); 3704601Swnj return; 3714601Swnj } 3724601Swnj /* NOTREACHED */ 3734601Swnj 3744601Swnj /* 3754601Swnj * Unwanted packed; free everything 3764601Swnj * but the header and return an rst. 3774601Swnj */ 3784601Swnj notwanted: 3794601Swnj m_freem(mp->m_next); 3804601Swnj mp->m_next = NULL; 3814601Swnj mp->m_len = sizeof(struct th); 3824601Swnj #define xchg(a,b) j=a; a=b; b=j 3834601Swnj xchg(n->t_d.s_addr, n->t_s.s_addr); xchg(n->t_dst, n->t_src); 3844601Swnj #undef xchg 3854601Swnj if (n->th_flags&TH_ACK) 3864601Swnj n->t_seq = n->t_ackno; 3874601Swnj else { 3884601Swnj n->t_ackno = htonl(ntohl(n->t_seq) + tlen - hlen); 3894601Swnj n->t_seq = 0; 3904601Swnj } 3914601Swnj n->th_flags = TH_RST; /* not TH_FIN, TH_SYN */ 3924601Swnj n->th_flags ^= TH_ACK; 3934601Swnj n->t_len = htons(TCPSIZE); 3944601Swnj n->t_off = 5; 3954601Swnj n->t_sum = cksum(mp, sizeof(struct th)); 3964601Swnj ((struct ip *)n)->ip_len = sizeof(struct th); 3974601Swnj ip_output(mp); 3984601Swnj netstat.t_badsegs++; 3994601Swnj } 4004601Swnj 4014601Swnj rcv_ctldat(tp, n, dataok) 4024601Swnj register struct tcb *tp; 4034601Swnj register struct th *n; 4044601Swnj { 4054601Swnj register sent; 4064601Swnj register struct ucb *up; 4074601Swnj register struct mbuf *m, *mn; 4084601Swnj register len; 4094601Swnj COUNT(RCV_CTLDAT); 4104601Swnj 4114601Swnj tp->tc_flags &= ~(TC_DROPPED_TXT|TC_ACK_DUE|TC_NEW_WINDOW); 4124601Swnj /* syn */ 4134601Swnj if ((tp->tc_flags&TC_SYN_RCVD) == 0 && (n->th_flags&TH_SYN)) { 4144601Swnj tp->irs = n->t_seq; 4154601Swnj tp->rcv_nxt = n->t_seq + 1; 4164601Swnj tp->snd_wl = tp->rcv_urp = tp->irs; 4174601Swnj tp->tc_flags |= (TC_SYN_RCVD|TC_ACK_DUE); 4184601Swnj } 4194601Swnj /* ack */ 4204601Swnj if ((n->th_flags&TH_ACK) && (tp->tc_flags&TC_SYN_RCVD) && 4214601Swnj n->t_ackno > tp->snd_una) { 4224601Swnj up = tp->t_ucb; 4234601Swnj 4244601Swnj /* update snd_una and snd_nxt */ 4254601Swnj tp->snd_una = n->t_ackno; 4264601Swnj if (tp->snd_una > tp->snd_nxt) 4274601Swnj tp->snd_nxt = tp->snd_una; 4284601Swnj 4294601Swnj /* if timed msg acked, set retrans time value */ 4304601Swnj if ((tp->tc_flags&TC_SYN_ACKED) && 4314601Swnj tp->snd_una > tp->t_xmt_val) { 4324601Swnj tp->t_xmtime = (tp->t_xmt != 0 ? tp->t_xmt : T_REXMT); 4334601Swnj if (tp->t_xmtime > T_REMAX) 4344601Swnj tp->t_xmtime = T_REMAX; 4354601Swnj } 4364601Swnj 4374601Swnj /* remove acked data from send buf */ 4384601Swnj len = tp->snd_una - tp->snd_off; 4394601Swnj m = up->uc_sbuf; 4404601Swnj while (len > 0 && m != NULL) 4414601Swnj if (m->m_len <= len) { 4424601Swnj len -= m->m_len; 4434601Swnj if (m->m_off > MMAXOFF) 4444601Swnj up->uc_ssize -= NMBPG; 4454601Swnj MFREE(m, mn); 4464601Swnj m = mn; 4474601Swnj up->uc_ssize--; 4484601Swnj } else { 4494601Swnj m->m_len -= len; 4504601Swnj m->m_off += len; 4514601Swnj break; 4524601Swnj } 4534601Swnj up->uc_sbuf = m; 4544601Swnj tp->snd_off = tp->snd_una; 4554601Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0 && 4564601Swnj (tp->snd_una > tp->iss)) { 4574601Swnj tp->tc_flags |= TC_SYN_ACKED; 4584601Swnj tp->t_init = 0; 4594601Swnj } 4604601Swnj if (tp->seq_fin != tp->iss && tp->snd_una > tp->seq_fin) 4614601Swnj tp->tc_flags &= ~TC_SND_FIN; 4624601Swnj tp->t_rexmt = 0; 4634601Swnj tp->t_rexmttl = 0; 4644601Swnj tp->tc_flags |= TC_CANCELLED; 4654601Swnj netwakeup(tp->t_ucb); /* wasteful */ 4664601Swnj } 4674601Swnj /* win */ 4684601Swnj if ((tp->tc_flags & TC_SYN_RCVD) && n->t_seq >= tp->snd_wl) { 4694601Swnj tp->snd_wl = n->t_seq; 4704601Swnj tp->snd_wnd = n->t_win; 4714601Swnj tp->tc_flags |= TC_NEW_WINDOW; 4724601Swnj tp->t_persist = 0; 4734601Swnj } 4744601Swnj if (dataok) { 4754601Swnj /* text */ 4764601Swnj if (n->t_len != 0) 4774601Swnj rcv_text(tp, n); 4784601Swnj /* urg */ 4794601Swnj if (n->th_flags&TH_URG) { 4804601Swnj unsigned urgent; 4814601Swnj 4824601Swnj urgent = n->t_urp + n->t_seq; 4834601Swnj if (tp->rcv_nxt < urgent) { 4844601Swnj if (tp->rcv_urp <= tp->rcv_nxt) 4854601Swnj to_user(tp->t_ucb, UURGENT); 4864601Swnj tp->rcv_urp = urgent; 4874601Swnj } 4884601Swnj } 4894601Swnj /* eol */ 4904601Swnj if ((n->th_flags&TH_EOL) && 4914601Swnj (tp->tc_flags&TC_DROPPED_TXT) == 0 && 4924601Swnj tp->t_rcv_prev != (struct th *)tp) { 4934601Swnj /* mark last mbuf */ 4944601Swnj m = dtom(tp->t_rcv_prev); 4954601Swnj if (m != NULL) { 4964601Swnj while (m->m_next != NULL) 4974601Swnj m = m->m_next; 4984601Swnj m->m_act = 4994601Swnj (struct mbuf *)(m->m_off + m->m_len - 1); 5004601Swnj } 5014601Swnj } 5024601Swnj } 5034601Swnj /* fin */ 5044601Swnj if ((n->th_flags&TH_FIN) && (tp->tc_flags&TC_DROPPED_TXT) == 0) { 5054601Swnj int last; 5064601Swnj 5074601Swnj if ((tp->tc_flags&TC_FIN_RCVD) == 0) { 5084601Swnj /* do we really have fin ? */ 5094601Swnj last = firstempty(tp); 5104601Swnj if (tp->t_rcv_prev == (struct th *)tp || 5114601Swnj last == t_end(tp->t_rcv_prev)) { 5124601Swnj tp->tc_flags |= TC_FIN_RCVD; 5134601Swnj netwakeup(tp->t_ucb); /* poke */ 5144601Swnj } 5154601Swnj if ((tp->tc_flags&TC_FIN_RCVD) && 5164601Swnj tp->rcv_nxt >= last) { 5174601Swnj tp->rcv_nxt = last + 1; /* fin seq */ 5184601Swnj tp->tc_flags |= TC_ACK_DUE; 5194601Swnj } 5204601Swnj } else 5214601Swnj tp->tc_flags |= TC_ACK_DUE; 5224601Swnj } 5234601Swnj 5244601Swnj /* respond */ 525*4671Swnj sent = 0; 5264601Swnj if (tp->tc_flags&TC_ACK_DUE) 5274601Swnj sent = send_ctl(tp); 528*4671Swnj else if (tp->tc_flags&TC_NEW_WINDOW) { 529*4671Swnj seq_t last = tp->snd_off; 530*4671Swnj up = tp->t_ucb; 531*4671Swnj for (m = up->uc_sbuf; m != NULL; m = m->m_next) 532*4671Swnj last += m->m_len; 533*4671Swnj if (tp->snd_nxt <= last || (tp->tc_flags&TC_SND_FIN)) 534*4671Swnj sent = send(tp); 535*4671Swnj } 5364601Swnj 5374601Swnj /* set for retrans */ 5384601Swnj if (!sent && tp->snd_una < tp->snd_nxt && 5394601Swnj (tp->tc_flags&TC_CANCELLED)) { 5404601Swnj tp->t_rexmt = tp->t_xmtime; 5414601Swnj tp->t_rexmttl = T_REXMTTL; 5424601Swnj tp->t_rexmt_val = tp->t_rtl_val = tp->snd_lst; 5434601Swnj tp->tc_flags &= ~TC_CANCELLED; 5444601Swnj } 5454601Swnj } 5464601Swnj 5474645Swnj rcv_text(tp, n) 5484601Swnj register struct tcb *tp; 5494645Swnj register struct th *n; 5504601Swnj { 5514645Swnj register int i; 5524601Swnj register struct th *p, *q; 5534645Swnj register struct mbuf *m; 5544645Swnj int overage; 5554601Swnj COUNT(RCV_TEXT); 5564601Swnj 5574645Swnj /* 5584645Swnj * Discard duplicate data already passed to user. 5594645Swnj */ 5604648Swnj if (SEQ_LT(n->t_seq, tp->rcv_nxt)) { 5614645Swnj i = tp->rcv_nxt - n->t_seq; 5624645Swnj if (i >= n->t_len) 5634645Swnj goto dropseg; 5644645Swnj n->t_seq += i; 5654645Swnj n->t_len -= i; 5664645Swnj m_adj(dtom(n), i); 5674601Swnj } 5684601Swnj 5694645Swnj /* 5704645Swnj * Find a segment which begins after this one does. 5714645Swnj */ 5724645Swnj for (q = tp->t_rcv_next; q != (struct th *)tp; q = q->t_next) 5734648Swnj if (SEQ_GT(q->t_seq, n->t_seq)) 5744645Swnj break; 5754601Swnj 5764645Swnj /* 5774645Swnj * If there is a preceding segment, it may provide some of 5784645Swnj * our data already. If so, drop the data from the incoming 5794645Swnj * segment. If it provides all of our data, drop us. 5804645Swnj */ 5814645Swnj if (q->t_prev != (struct th *)tp) { 5824648Swnj /* conversion to int (in i) handles seq wraparound */ 5834645Swnj i = q->t_prev->t_seq + q->t_prev->t_len - n->t_seq; 5844645Swnj if (i > 0) { 5854645Swnj if (i >= n->t_len) 5864645Swnj goto dropseg; 5874645Swnj m_adj(dtom(tp), i); 5884645Swnj n->t_len -= i; 5894645Swnj n->t_seq += i; 5904601Swnj } 5914601Swnj } 5924601Swnj 5934645Swnj /* 5944645Swnj * While we overlap succeeding segments trim them or, 5954645Swnj * if they are completely covered, dequeue them. 5964645Swnj */ 5974648Swnj while (q != (struct th *)tp && SEQ_GT(n->t_seq + n->t_len, q->t_seq)) { 5984645Swnj i = (n->t_seq + n->t_len) - q->t_seq; 5994645Swnj if (i < q->t_len) { 6004645Swnj q->t_len -= i; 6014645Swnj m_adj(dtom(q), i); 6024645Swnj break; 6034601Swnj } 6044645Swnj q = q->t_next; 6054645Swnj m_freem(dtom(q->t_prev)); 6064645Swnj remque(q->t_prev); 6074645Swnj } 6084601Swnj 6094645Swnj /* 6104645Swnj * Stick new segment in its place. 6114645Swnj */ 6124645Swnj insque(n, q->t_prev); 6134656Swnj tp->seqcnt += n->t_len; 6144601Swnj 6154601Swnj #ifdef notdef 6164645Swnj /* 6174645Swnj * Calculate available space and discard segments for 6184645Swnj * which there is too much. 6194645Swnj */ 6204645Swnj q = tp->t_rcv_prev; 6214648Swnj overage = 6224648Swnj (tp->t_socket->uc_rcc + tp->rcv_seqcnt) - tp->t_socket->uc_rhiwat; 6234645Swnj if (overage > 0) 6244645Swnj for (;;) { 6254645Swnj i = MIN(q->t_len, overage); 6264645Swnj overage -= i; 6274645Swnj q->t_len -= i; 6284645Swnj m_adj(q, -i); 6294645Swnj if (q == n) 6304645Swnj tp->tc_flags |= TC_DROPPED_TXT; 6314645Swnj if (q->t_len) 6324645Swnj break; 6334645Swnj if (q == n) 6344648Swnj panic("tcp_text dropall"); 6354645Swnj q = q->t_prev; 6364645Swnj remque(q->t_next); 6374645Swnj } 6384645Swnj #endif 6394601Swnj 6404645Swnj /* 6414648Swnj * Advance rcv_next through 6424648Swnj * newly completed sequence space 6434648Swnj * and return forcing an ack. 6444645Swnj */ 6454645Swnj while (n->t_seq == tp->rcv_nxt) { 6464648Swnj /* present data belongs here */ 6474645Swnj tp->rcv_nxt += n->t_len; 6484645Swnj n = n->t_next; 6494645Swnj if (n == (struct th *)tp) 6504645Swnj break; 6514645Swnj } 6524645Swnj tp->tc_flags |= (TC_ACK_DUE|TC_NET_KEEP); 6534645Swnj return; 6544601Swnj 6554645Swnj dropseg: 6564648Swnj /* don't set TC_NET_KEEP, so that mbuf's will get dropped */ 6574645Swnj return; 6584601Swnj } 6594601Swnj 6604656Swnj #define socket ucb /* ### */ 6614656Swnj #define t_socket t_ucb /* ### */ 6624656Swnj 6634601Swnj present_data(tp) 6644601Swnj register struct tcb *tp; 6654601Swnj { 6664601Swnj register struct th *t; 6674656Swnj register struct socket *up; 6684601Swnj register struct mbuf *m, **mp; 6694601Swnj seq_t ready; 6704601Swnj COUNT(PRESENT_DATA); 6714601Swnj 6724601Swnj /* connection must be synced and data available for user */ 6734656Swnj if ((tp->tc_flags&TC_SYN_ACKED) == 0) 6744601Swnj return; 6754656Swnj up = tp->t_socket; 6764601Swnj mp = &up->uc_rbuf; 6774601Swnj while (*mp) 6784601Swnj mp = &(*mp)->m_next; 6794656Swnj t = tp->t_rcv_next; 6804656Swnj /* SHOULD PACK DATA IN HERE */ 6814656Swnj while (t != (struct th *)tp && t->t_seq < tp->rcv_nxt) { 6824656Swnj remque(t); 6834601Swnj m = dtom(t); 6844656Swnj up->uc_rcc += t->t_len; 6854656Swnj tp->seqcnt -= t->t_len; 6864656Swnj if (tp->seqcnt < 0) panic("present_data"); 6874601Swnj t = t->t_next; 6884601Swnj while (m) { 6894601Swnj if (m->m_len == 0) { 6904601Swnj m = m_free(m); 6914601Swnj continue; 6924601Swnj } 6934656Swnj *mp = m; 6944601Swnj mp = &m->m_next; 6954601Swnj m = *mp; 6964601Swnj } 6974601Swnj } 6984656Swnj if (up->uc_rcc != 0) 6994601Swnj netwakeup(up); 7004656Swnj if ((tp->tc_flags&TC_FIN_RCVD) && /* ### */ 7014656Swnj (tp->tc_flags&TC_USR_CLOSED) == 0 && /* ### */ 7024656Swnj rcv_empty(tp)) /* ### */ 7034656Swnj to_user(up, UCLOSED); /* ### */ 7044601Swnj } 705