1*5223Swnj /* tcp_input.c 1.37 81/12/09 */ 24601Swnj 34601Swnj #include "../h/param.h" 44601Swnj #include "../h/systm.h" 54663Swnj #include "../h/mbuf.h" 65085Swnj #include "../h/protosw.h" 74663Swnj #include "../h/socket.h" 84803Swnj #include "../h/socketvar.h" 95085Swnj #include "../net/in.h" 105085Swnj #include "../net/in_pcb.h" 115085Swnj #include "../net/in_systm.h" 125085Swnj #include "../net/if.h" 134803Swnj #include "../net/ip.h" 144899Swnj #include "../net/ip_var.h" 154803Swnj #include "../net/tcp.h" 164803Swnj #include "../net/tcp_fsm.h" 175085Swnj #include "../net/tcp_seq.h" 185085Swnj #include "../net/tcp_timer.h" 194803Swnj #include "../net/tcp_var.h" 205085Swnj #include "../net/tcpip.h" 215109Swnj #include "../errno.h" 224601Swnj 234679Swnj int tcpcksum = 1; 244601Swnj 255065Swnj /* 265065Swnj * TCP input routine, follows pages 65-76 of the 275065Swnj * protocol specification dated September, 1981 very closely. 285065Swnj */ 294924Swnj tcp_input(m0) 304924Swnj struct mbuf *m0; 314601Swnj { 324924Swnj register struct tcpiphdr *ti; 334924Swnj struct inpcb *inp; 344924Swnj register struct mbuf *m; 354924Swnj int len, tlen, off; 364924Swnj register struct tcpcb *tp; 374924Swnj register int tiflags; 384803Swnj struct socket *so; 395109Swnj int todrop, acked; 404924Swnj 414601Swnj COUNT(TCP_INPUT); 424924Swnj /* 434924Swnj * Get ip and tcp header together in first mbuf. 44*5223Swnj * Note: ip leaves ip header in first mbuf. 454924Swnj */ 464924Swnj m = m0; 475020Sroot ti = mtod(m, struct tcpiphdr *); 48*5223Swnj if (((struct ip *)ti)->ip_len > sizeof (struct ip)) 495208Swnj ip_stripoptions((struct ip *)ti, (struct mbuf *)0); 505085Swnj if (m->m_len < sizeof (struct tcpiphdr)) { 515085Swnj if (m_pullup(m, sizeof (struct tcpiphdr)) == 0) { 525085Swnj tcpstat.tcps_hdrops++; 535085Swnj goto drop; 545085Swnj } 555085Swnj ti = mtod(m, struct tcpiphdr *); 565085Swnj } 574601Swnj 584601Swnj /* 594924Swnj * Checksum extended tcp header and data. 604601Swnj */ 614924Swnj tlen = ((struct ip *)ti)->ip_len; 624924Swnj len = sizeof (struct ip) + tlen; 634679Swnj if (tcpcksum) { 644924Swnj ti->ti_next = ti->ti_prev = 0; 654924Swnj ti->ti_x1 = 0; 66*5223Swnj ti->ti_len = (u_short)tlen; 67*5223Swnj #if vax 68*5223Swnj ti->ti_len = htons(ti->ti_len); 69*5223Swnj #endif 705085Swnj if ((ti->ti_sum = in_cksum(m, len)) != 0xffff) { 714924Swnj tcpstat.tcps_badsum++; 725065Swnj printf("tcp cksum %x\n", ti->ti_sum); 735085Swnj goto drop; 744601Swnj } 754601Swnj } 764601Swnj 774601Swnj /* 784924Swnj * Check that tcp offset makes sense, 794924Swnj * process tcp options and adjust length. 804601Swnj */ 814924Swnj off = ti->ti_off << 2; 824924Swnj if (off < sizeof (struct tcphdr) || off > ti->ti_len) { 834924Swnj tcpstat.tcps_badoff++; 845085Swnj goto drop; 854924Swnj } 864924Swnj ti->ti_len = tlen - off; 875085Swnj #if 0 885085Swnj if (off > sizeof (struct tcphdr) >> 2) 895085Swnj tcp_options(ti); 905085Swnj #endif 915065Swnj tiflags = ti->ti_flags; 924924Swnj 934924Swnj /* 945085Swnj * Convert tcp protocol specific fields to host format. 955085Swnj */ 965085Swnj ti->ti_seq = ntohl(ti->ti_seq); 975085Swnj ti->ti_ack = ntohl(ti->ti_ack); 985085Swnj ti->ti_win = ntohs(ti->ti_win); 995085Swnj ti->ti_urp = ntohs(ti->ti_urp); 1005085Swnj 1015085Swnj /* 1024924Swnj * Locate pcb for segment. 1034924Swnj */ 1045065Swnj inp = in_pcblookup 1055065Swnj (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport); 1065065Swnj 1075065Swnj /* 1085065Swnj * If the state is CLOSED (i.e., TCB does not exist) then 1095065Swnj * all data in the incoming segment is discarded. (p. 65). 1105065Swnj */ 1114884Swnj if (inp == 0) 1125085Swnj goto dropwithreset; 1135065Swnj tp = intotcpcb(inp); 1145065Swnj if (tp == 0) 1155085Swnj goto dropwithreset; 1165109Swnj so = inp->inp_socket; 1174601Swnj 1184601Swnj /* 1195162Swnj * Segment received on connection. 1205162Swnj * Reset idle time and keep-alive timer. 1215162Swnj */ 1225162Swnj tp->t_idle = 0; 1235162Swnj tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 1245162Swnj 1255162Swnj /* 1265085Swnj * Calculate amount of space in receive window, 1275085Swnj * and then do TCP input processing. 1284601Swnj */ 1295085Swnj tp->rcv_wnd = sbspace(&so->so_rcv); 1304601Swnj 1314601Swnj switch (tp->t_state) { 1324601Swnj 1335065Swnj /* 1345065Swnj * If the state is LISTEN then ignore segment if it contains an RST. 1355065Swnj * If the segment contains an ACK then it is bad and send a RST. 1365065Swnj * If it does not contain a SYN then it is not interesting; drop it. 1375085Swnj * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial 1385065Swnj * tp->iss, and send a segment: 1395085Swnj * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> 1405065Swnj * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. 1415065Swnj * Fill in remote peer address fields if not previously specified. 1425065Swnj * Enter SYN_RECEIVED state, and process any other fields of this 1435065Swnj * segment in this state. (p. 65) 1445065Swnj */ 1455065Swnj case TCPS_LISTEN: 1465065Swnj if (tiflags & TH_RST) 1475065Swnj goto drop; 1485065Swnj if (tiflags & TH_ACK) 1495085Swnj goto dropwithreset; 1505065Swnj if ((tiflags & TH_SYN) == 0) 1515065Swnj goto drop; 1525085Swnj tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 1535065Swnj tp->irs = ti->ti_seq; 1545085Swnj tcp_sendseqinit(tp); 1555085Swnj tcp_rcvseqinit(tp); 1565065Swnj tp->t_state = TCPS_SYN_RECEIVED; 1575065Swnj if (inp->inp_faddr.s_addr == 0) { 1585065Swnj inp->inp_faddr = ti->ti_src; 1595065Swnj inp->inp_fport = ti->ti_sport; 1604601Swnj } 1615085Swnj goto trimthenstep6; 1624601Swnj 1635065Swnj /* 1645065Swnj * If the state is SYN_SENT: 1655065Swnj * if seg contains an ACK, but not for our SYN, drop the input. 1665065Swnj * if seg contains a RST, then drop the connection. 1675065Swnj * if seg does not contain SYN, then drop it. 1685065Swnj * Otherwise this is an acceptable SYN segment 1695065Swnj * initialize tp->rcv_nxt and tp->irs 1705065Swnj * if seg contains ack then advance tp->snd_una 1715065Swnj * if SYN has been acked change to ESTABLISHED else SYN_RCVD state 1725065Swnj * arrange for segment to be acked (eventually) 1735065Swnj * continue processing rest of data/controls, beginning with URG 1745065Swnj */ 1755065Swnj case TCPS_SYN_SENT: 1765065Swnj if ((tiflags & TH_ACK) && 1775065Swnj (SEQ_LEQ(ti->ti_ack, tp->iss) || 1785085Swnj SEQ_GT(ti->ti_ack, tp->snd_nxt))) 1795085Swnj goto dropwithreset; 1805065Swnj if (tiflags & TH_RST) { 1815065Swnj if (tiflags & TH_ACK) 1825085Swnj tcp_drop(tp, ECONNRESET); 1835065Swnj goto drop; 1844601Swnj } 1855065Swnj if ((tiflags & TH_SYN) == 0) 1865065Swnj goto drop; 1875085Swnj tp->iss = ti->ti_ack; 1885085Swnj tcp_sendseqinit(tp); 1895065Swnj tp->irs = ti->ti_seq; 1905085Swnj tcp_rcvseqinit(tp); 1915085Swnj tp->t_flags |= TF_ACKNOW; 1925162Swnj if (SEQ_GT(tp->snd_una, tp->iss)) { 1935065Swnj tp->t_state = TCPS_ESTABLISHED; 1945162Swnj (void) tcp_reass(tp, (struct tcpiphdr *)0); 1955162Swnj } else 1965085Swnj tp->t_state = TCPS_SYN_RECEIVED; 1975085Swnj goto trimthenstep6; 1985085Swnj 1995085Swnj trimthenstep6: 2005085Swnj /* 2015085Swnj * If had syn, advance ti->ti_seq to correspond 2025085Swnj * to first data byte. 2035085Swnj */ 2045085Swnj if (tiflags & TH_SYN) 2055085Swnj ti->ti_seq++; 2065085Swnj 2075085Swnj /* 2085085Swnj * If data, trim to stay within window, 2095085Swnj * dropping FIN if necessary. 2105085Swnj */ 2115085Swnj if (ti->ti_len > tp->rcv_wnd) { 2125085Swnj todrop = ti->ti_len - tp->rcv_wnd; 2135085Swnj m_adj(m, -todrop); 2145085Swnj ti->ti_len = tp->rcv_wnd; 2155085Swnj ti->ti_flags &= ~TH_FIN; 2165065Swnj } 2175085Swnj goto step6; 2185065Swnj } 2194601Swnj 2205065Swnj /* 2215065Swnj * States other than LISTEN or SYN_SENT. 2225065Swnj * First check that at least some bytes of segment are within 2235065Swnj * receive window. 2245065Swnj */ 2255065Swnj if (tp->rcv_wnd == 0) { 2265065Swnj /* 2275065Swnj * If window is closed can only take segments at 2285065Swnj * window edge, and have to drop data and EOL from 2295065Swnj * incoming segments. 2305065Swnj */ 2315065Swnj if (tp->rcv_nxt != ti->ti_seq) 2325065Swnj goto dropafterack; 2335085Swnj if (ti->ti_len > 0) { 2345085Swnj ti->ti_len = 0; 2355085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 2365065Swnj } 2375065Swnj } else { 2385065Swnj /* 2395065Swnj * If segment begins before rcv_next, drop leading 2405065Swnj * data (and SYN); if nothing left, just ack. 2415065Swnj */ 2425065Swnj if (SEQ_GT(tp->rcv_nxt, ti->ti_seq)) { 2435085Swnj todrop = tp->rcv_nxt - ti->ti_seq; 2445085Swnj if (tiflags & TH_SYN) { 2455085Swnj ti->ti_seq++; 2465085Swnj if (ti->ti_urp > 1) 2475085Swnj ti->ti_urp--; 2485085Swnj else 2495085Swnj tiflags &= ~TH_URG; 2505085Swnj todrop--; 2515085Swnj } 2525065Swnj if (todrop > ti->ti_len) 2535065Swnj goto dropafterack; 2545065Swnj m_adj(m, todrop); 2555065Swnj ti->ti_seq += todrop; 2565065Swnj ti->ti_len -= todrop; 2575085Swnj if (ti->ti_urp > todrop) 2585085Swnj ti->ti_urp -= todrop; 2595085Swnj else { 2605085Swnj tiflags &= ~TH_URG; 2615085Swnj /* ti->ti_flags &= ~TH_URG; */ 2625085Swnj /* ti->ti_urp = 0; */ 2635085Swnj } 2645085Swnj /* tiflags &= ~TH_SYN; */ 2655085Swnj /* ti->ti_flags &= ~TH_SYN; */ 2665065Swnj } 2675065Swnj /* 2685065Swnj * If segment ends after window, drop trailing data 2695085Swnj * (and PUSH and FIN); if nothing left, just ACK. 2705065Swnj */ 2715065Swnj if (SEQ_GT(ti->ti_seq+ti->ti_len, tp->rcv_nxt+tp->rcv_wnd)) { 2725085Swnj todrop = 2735065Swnj ti->ti_seq+ti->ti_len - (tp->rcv_nxt+tp->rcv_wnd); 2745065Swnj if (todrop > ti->ti_len) 2755065Swnj goto dropafterack; 2765065Swnj m_adj(m, -todrop); 2775065Swnj ti->ti_len -= todrop; 2785085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 2795065Swnj } 2805065Swnj } 2814601Swnj 2825065Swnj /* 2835065Swnj * If the RST bit is set examine the state: 2845065Swnj * SYN_RECEIVED STATE: 2855065Swnj * If passive open, return to LISTEN state. 2865065Swnj * If active open, inform user that connection was refused. 2875065Swnj * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: 2885065Swnj * Inform user that connection was reset, and close tcb. 2895065Swnj * CLOSING, LAST_ACK, TIME_WAIT STATES 2905065Swnj * Close the tcb. 2915065Swnj */ 2925065Swnj if (tiflags&TH_RST) switch (tp->t_state) { 2935065Swnj 2945065Swnj case TCPS_SYN_RECEIVED: 2955065Swnj if (inp->inp_socket->so_options & SO_ACCEPTCONN) { 2965085Swnj tp->t_state = TCPS_LISTEN; 2975085Swnj inp->inp_faddr.s_addr = 0; 2985065Swnj goto drop; 2994601Swnj } 3005085Swnj tcp_drop(tp, ECONNREFUSED); 3015065Swnj goto drop; 3024601Swnj 3035065Swnj case TCPS_ESTABLISHED: 3045065Swnj case TCPS_FIN_WAIT_1: 3055065Swnj case TCPS_FIN_WAIT_2: 3065065Swnj case TCPS_CLOSE_WAIT: 3075065Swnj tcp_drop(tp, ECONNRESET); 3085065Swnj goto drop; 3095065Swnj 3105065Swnj case TCPS_CLOSING: 3115065Swnj case TCPS_LAST_ACK: 3125065Swnj case TCPS_TIME_WAIT: 3135065Swnj tcp_close(tp); 3145065Swnj goto drop; 3154601Swnj } 3164601Swnj 3174601Swnj /* 3185065Swnj * If a SYN is in the window, then this is an 3195065Swnj * error and we send an RST and drop the connection. 3204601Swnj */ 3215065Swnj if (tiflags & TH_SYN) { 3225085Swnj tcp_drop(tp, ECONNABORTED); 3235085Swnj goto dropwithreset; 3244601Swnj } 3254601Swnj 3264601Swnj /* 3275065Swnj * If the ACK bit is off we drop the segment and return. 3284601Swnj */ 3295085Swnj if ((tiflags & TH_ACK) == 0) 3305065Swnj goto drop; 3315065Swnj 3325065Swnj /* 3335065Swnj * Ack processing. 3345065Swnj */ 3354601Swnj switch (tp->t_state) { 3364601Swnj 3375065Swnj /* 3385065Swnj * In SYN_RECEIVED state if the ack ACKs our SYN then enter 3395065Swnj * ESTABLISHED state and continue processing, othewise 3405065Swnj * send an RST. 3415065Swnj */ 3425065Swnj case TCPS_SYN_RECEIVED: 3435085Swnj if (SEQ_GT(tp->snd_una, ti->ti_ack) || 3445085Swnj SEQ_GT(ti->ti_ack, tp->snd_nxt)) 3455085Swnj goto dropwithreset; 3465085Swnj soisconnected(so); 3475085Swnj tp->t_state = TCPS_ESTABLISHED; 3485162Swnj (void) tcp_reass(tp, (struct tcpiphdr *)0); 3495085Swnj /* fall into ... */ 3504601Swnj 3515065Swnj /* 3525065Swnj * In ESTABLISHED state: drop duplicate ACKs; ACK out of range 3535065Swnj * ACKs. If the ack is in the range 3545065Swnj * tp->snd_una < ti->ti_ack <= tp->snd_nxt 3555065Swnj * then advance tp->snd_una to ti->ti_ack and drop 3565065Swnj * data from the retransmission queue. If this ACK reflects 3575065Swnj * more up to date window information we update our window information. 3585065Swnj */ 3595065Swnj case TCPS_ESTABLISHED: 3605065Swnj case TCPS_FIN_WAIT_1: 3615065Swnj case TCPS_FIN_WAIT_2: 3625065Swnj case TCPS_CLOSE_WAIT: 3635065Swnj case TCPS_CLOSING: 3645085Swnj #define ourfinisacked (acked > 0) 3655085Swnj 3665065Swnj if (SEQ_LT(ti->ti_ack, tp->snd_una)) 3675065Swnj break; 3685065Swnj if (SEQ_GT(ti->ti_ack, tp->snd_nxt)) 3695065Swnj goto dropafterack; 3705085Swnj acked = ti->ti_ack - tp->snd_una; 3715085Swnj if (acked > so->so_snd.sb_cc) { 3725085Swnj sbflush(&so->so_snd); 3735085Swnj acked -= so->so_snd.sb_cc; 3745162Swnj /* if acked our FIN is acked */ 3755085Swnj } else { 3765085Swnj sbdrop(&so->so_snd, acked); 3775085Swnj acked = 0; 3785085Swnj } 3795162Swnj 3805162Swnj /* 3815162Swnj * If transmit timer is running and timed sequence 3825162Swnj * number was acked, update smoothed round trip time. 3835162Swnj */ 3845162Swnj if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) { 3855162Swnj tp->t_srtt = 3865162Swnj tcp_beta * tp->t_srtt + 3875162Swnj (1 - tcp_beta) * tp->t_rtt; 3885162Swnj tp->t_rtt = 0; 3895162Swnj } 3905162Swnj 3915065Swnj tp->snd_una = ti->ti_ack; 3925085Swnj 3935085Swnj /* 3945085Swnj * Update window information. 3955085Swnj */ 3965065Swnj if (SEQ_LT(tp->snd_wl1, ti->ti_seq) || 3975085Swnj tp->snd_wl1==ti->ti_seq && SEQ_LEQ(tp->snd_wl2,ti->ti_seq)) { 3985065Swnj tp->snd_wnd = ti->ti_win; 3995065Swnj tp->snd_wl1 = ti->ti_seq; 4005065Swnj tp->snd_wl2 = ti->ti_ack; 4014601Swnj } 4024601Swnj 4034601Swnj switch (tp->t_state) { 4044601Swnj 4055065Swnj /* 4065065Swnj * In FIN_WAIT_1 STATE in addition to the processing 4075065Swnj * for the ESTABLISHED state if our FIN is now acknowledged 4085085Swnj * then enter FIN_WAIT_2. 4095065Swnj */ 4105065Swnj case TCPS_FIN_WAIT_1: 4115085Swnj if (ourfinisacked) 4125085Swnj tp->t_state = TCPS_FIN_WAIT_2; 4134601Swnj break; 4144601Swnj 4155065Swnj /* 4165065Swnj * In CLOSING STATE in addition to the processing for 4175065Swnj * the ESTABLISHED state if the ACK acknowledges our FIN 4185065Swnj * then enter the TIME-WAIT state, otherwise ignore 4195065Swnj * the segment. 4205065Swnj */ 4215065Swnj case TCPS_CLOSING: 4225085Swnj if (ourfinisacked) 4235065Swnj tp->t_state = TCPS_TIME_WAIT; 4245085Swnj goto drop; 4254601Swnj 4265065Swnj /* 4275085Swnj * The only thing that can arrive in LAST_ACK state 4285085Swnj * is an acknowledgment of our FIN. If our FIN is now 4295085Swnj * acknowledged, delete the TCB, enter the closed state 4305085Swnj * and return. 4315065Swnj */ 4325065Swnj case TCPS_LAST_ACK: 4335085Swnj if (ourfinisacked) 4345065Swnj tcp_close(tp); 4355065Swnj goto drop; 4364601Swnj 4375065Swnj /* 4385065Swnj * In TIME_WAIT state the only thing that should arrive 4395065Swnj * is a retransmission of the remote FIN. Acknowledge 4405065Swnj * it and restart the finack timer. 4415065Swnj */ 4425065Swnj case TCPS_TIME_WAIT: 4435162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 4445065Swnj goto dropafterack; 4454601Swnj } 4465085Swnj #undef ourfinisacked 4475085Swnj } 4484601Swnj 4495065Swnj step6: 4505065Swnj /* 4515065Swnj * If an URG bit is set in the segment and is greater than the 4525065Swnj * current known urgent pointer, then signal the user that the 4535065Swnj * remote side has urgent data. This should not happen 4545065Swnj * in CLOSE_WAIT, CLOSING, LAST-ACK or TIME_WAIT STATES since 4555065Swnj * a FIN has been received from the remote side. In these states 4565065Swnj * we ignore the URG. 4575065Swnj */ 4585085Swnj if ((tiflags & TH_URG) == 0 && TCPS_HAVERCVDFIN(tp->t_state) == 0) 4595085Swnj if (SEQ_GT(ti->ti_urp, tp->rcv_up)) { 4605065Swnj tp->rcv_up = ti->ti_urp; 4615085Swnj #if 0 4625065Swnj soisurgendata(so); /* XXX */ 4635085Swnj #endif 4644601Swnj } 4654601Swnj 4664601Swnj /* 4675065Swnj * Process the segment text, merging it into the TCP sequencing queue, 4685065Swnj * and arranging for acknowledgment of receipt if necessary. 4695065Swnj * This process logically involves adjusting tp->rcv_wnd as data 4705065Swnj * is presented to the user (this happens in tcp_usrreq.c, 4715065Swnj * case PRU_RCVD). If a FIN has already been received on this 4725065Swnj * connection then we just ignore the text. 4734601Swnj */ 4745065Swnj if (ti->ti_len) { 4755085Swnj if (TCPS_HAVERCVDFIN(tp->t_state)) 4765065Swnj goto drop; 4775085Swnj off += sizeof (struct ip); /* drop IP header */ 4785085Swnj m->m_off += off; 4795085Swnj m->m_len -= off; 4805065Swnj tiflags = tcp_reass(tp, ti); 4815085Swnj tp->t_flags |= TF_ACKNOW; /* XXX TF_DELACK */ 4825085Swnj } else 4834924Swnj m_freem(m); 4844601Swnj 4854601Swnj /* 4865065Swnj * If FIN is received then if we haven't received SYN and 4875065Swnj * therefore can't validate drop the segment. Otherwise ACK 4885065Swnj * the FIN and let the user know that the connection is closing. 4894601Swnj */ 4905085Swnj if ((tiflags & TH_FIN)) { 4915074Swnj if (TCPS_HAVERCVDSYN(tp->t_state) == 0) 4925074Swnj goto drop; 4935074Swnj socantrcvmore(so); 4945065Swnj tp->t_flags |= TF_ACKNOW; 4955065Swnj tp->rcv_nxt++; 4965065Swnj switch (tp->t_state) { 4974601Swnj 4985065Swnj /* 4995065Swnj * In SYN_RECEIVED and ESTABLISHED STATES 5005065Swnj * enter the CLOSE_WAIT state. 5014884Swnj */ 5025065Swnj case TCPS_SYN_RECEIVED: 5035065Swnj case TCPS_ESTABLISHED: 5045065Swnj tp->t_state = TCPS_CLOSE_WAIT; 5055065Swnj break; 5064884Swnj 5075065Swnj /* 5085085Swnj * If still in FIN_WAIT_1 STATE FIN has not been acked so 5095085Swnj * enter the CLOSING state. 5104884Swnj */ 5115065Swnj case TCPS_FIN_WAIT_1: 5125085Swnj tp->t_state = TCPS_CLOSING; 5135065Swnj break; 5144601Swnj 5155065Swnj /* 5165065Swnj * In FIN_WAIT_2 state enter the TIME_WAIT state, 5175065Swnj * starting the time-wait timer, turning off the other 5185065Swnj * standard timers. 5195065Swnj */ 5205065Swnj case TCPS_FIN_WAIT_2: 5215085Swnj tp->t_state = TCPS_TIME_WAIT;; 5225074Swnj tcp_canceltimers(tp); 5235162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 5245065Swnj break; 5255065Swnj 5264884Swnj /* 5275065Swnj * In TIME_WAIT state restart the 2 MSL time_wait timer. 5284884Swnj */ 5295065Swnj case TCPS_TIME_WAIT: 5305162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 5315065Swnj break; 5325085Swnj } 5334601Swnj } 5345085Swnj 5355085Swnj /* 5365085Swnj * Return any desired output. 5375085Swnj */ 5385085Swnj tcp_output(tp); 5395065Swnj return; 5405085Swnj 5415065Swnj dropafterack: 5425085Swnj /* 5435085Swnj * Generate an ACK, then drop incoming segment. 5445085Swnj * Make ACK reflect our state. 5455085Swnj */ 5465085Swnj if (tiflags & TH_RST) 5475085Swnj goto drop; 5485085Swnj tcp_respond(ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK); 5495085Swnj goto drop; 5505085Swnj 5515085Swnj dropwithreset: 5525085Swnj /* 5535085Swnj * Generate a RST, then drop incoming segment. 5545085Swnj * Make ACK acceptable to originator of segment. 5555085Swnj */ 5565085Swnj if (tiflags & TH_RST) 5575085Swnj goto drop; 5585085Swnj if (tiflags & TH_ACK) 5595109Swnj tcp_respond(ti, (tcp_seq)0, ti->ti_ack, TH_RST); 5605085Swnj else { 5615085Swnj if (tiflags & TH_SYN) 5625085Swnj ti->ti_len++; 5635109Swnj tcp_respond(ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK); 5645085Swnj } 5655085Swnj goto drop; 5665085Swnj 5675065Swnj drop: 5685085Swnj /* 5695085Swnj * Drop space held by incoming segment and return. 5705085Swnj */ 5715065Swnj m_freem(m); 5725065Swnj } 5735065Swnj 5745065Swnj /* 5755065Swnj * Insert segment ti into reassembly queue of tcp with 5765065Swnj * control block tp. Return TH_FIN if reassembly now includes 5775065Swnj * a segment with FIN. 5785065Swnj */ 5795109Swnj tcp_reass(tp, ti) 5805065Swnj register struct tcpcb *tp; 5815065Swnj register struct tcpiphdr *ti; 5825065Swnj { 5835065Swnj register struct tcpiphdr *q; 5845085Swnj struct socket *so = tp->t_inpcb->inp_socket; 5855065Swnj int flags = 0; /* no FIN */ 5865085Swnj COUNT(TCP_REASS); 5875065Swnj 5885065Swnj /* 5895162Swnj * Call with ti==0 after become established to 5905162Swnj * force pre-ESTABLISHED data up to user socket. 5915065Swnj */ 5925162Swnj if (ti == 0) 5935065Swnj goto present; 5944601Swnj 5955065Swnj /* 5965065Swnj * Find a segment which begins after this one does. 5975065Swnj */ 5985065Swnj for (q = tp->seg_next; q != (struct tcpiphdr *)tp; 5995065Swnj q = (struct tcpiphdr *)q->ti_next) 6005065Swnj if (SEQ_GT(q->ti_seq, ti->ti_seq)) 6015065Swnj break; 6024601Swnj 6035065Swnj /* 6045065Swnj * If there is a preceding segment, it may provide some of 6055065Swnj * our data already. If so, drop the data from the incoming 6065065Swnj * segment. If it provides all of our data, drop us. 6075065Swnj */ 6085065Swnj if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { 6095065Swnj register int i; 6105065Swnj q = (struct tcpiphdr *)(q->ti_prev); 6115065Swnj /* conversion to int (in i) handles seq wraparound */ 6125065Swnj i = q->ti_seq + q->ti_len - ti->ti_seq; 6135065Swnj if (i > 0) { 6144924Swnj if (i >= ti->ti_len) 6155065Swnj goto drop; 6165065Swnj m_adj(dtom(tp), i); 6175065Swnj ti->ti_len -= i; 6184924Swnj ti->ti_seq += i; 6194601Swnj } 6205065Swnj q = (struct tcpiphdr *)(q->ti_next); 6215065Swnj } 6224601Swnj 6235065Swnj /* 6245065Swnj * While we overlap succeeding segments trim them or, 6255065Swnj * if they are completely covered, dequeue them. 6265065Swnj */ 6275065Swnj while (q != (struct tcpiphdr *)tp && 6285065Swnj SEQ_GT(ti->ti_seq + ti->ti_len, q->ti_seq)) { 6295065Swnj register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; 6305065Swnj if (i < q->ti_len) { 6315065Swnj q->ti_len -= i; 6325065Swnj m_adj(dtom(q), i); 6335065Swnj break; 6344601Swnj } 6355065Swnj q = (struct tcpiphdr *)q->ti_next; 6365065Swnj m_freem(dtom(q->ti_prev)); 6375065Swnj remque(q->ti_prev); 6385065Swnj } 6394601Swnj 6405065Swnj /* 6415065Swnj * Stick new segment in its place. 6425065Swnj */ 6435065Swnj insque(ti, q->ti_prev); 6444601Swnj 6455065Swnj /* 6465065Swnj * Advance rcv_next through newly completed sequence space. 6475065Swnj */ 6485065Swnj while (ti->ti_seq == tp->rcv_nxt) { 6495065Swnj tp->rcv_nxt += ti->ti_len; 6505065Swnj flags = ti->ti_flags & TH_FIN; 6515065Swnj ti = (struct tcpiphdr *)ti->ti_next; 6525065Swnj if (ti == (struct tcpiphdr *)tp) 6535065Swnj break; 6544679Swnj } 6554679Swnj 6565065Swnj present: 6575065Swnj /* 6585065Swnj * Present data to user. 6595065Swnj */ 6605085Swnj if (tp->t_state < TCPS_ESTABLISHED) 6615065Swnj return (flags); 6624924Swnj ti = tp->seg_next; 6634924Swnj while (ti != (struct tcpiphdr *)tp && ti->ti_seq < tp->rcv_nxt) { 6644924Swnj remque(ti); 6654924Swnj sbappend(&so->so_rcv, dtom(ti)); 6664924Swnj ti = (struct tcpiphdr *)ti->ti_next; 6674601Swnj } 6685074Swnj if (so->so_state & SS_CANTRCVMORE) 6695074Swnj sbflush(&so->so_rcv); 6705074Swnj else 6715074Swnj sorwakeup(so); 6725065Swnj return (flags); 6735065Swnj drop: 6745065Swnj m_freem(dtom(ti)); 6755065Swnj return (flags); 6764601Swnj } 677