1*5109Swnj /* tcp_input.c 1.33 81/11/29 */ 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" 21*5109Swnj #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; 39*5109Swnj int todrop, acked; 404924Swnj 414601Swnj COUNT(TCP_INPUT); 424924Swnj /* 434924Swnj * Get ip and tcp header together in first mbuf. 444924Swnj */ 454924Swnj m = m0; 465020Sroot ti = mtod(m, struct tcpiphdr *); 475020Sroot if (ti->ti_len > sizeof (struct ip)) 485020Sroot ip_stripoptions((struct ip *)ti, (char *)0); 495085Swnj if (m->m_len < sizeof (struct tcpiphdr)) { 505085Swnj if (m_pullup(m, sizeof (struct tcpiphdr)) == 0) { 515085Swnj tcpstat.tcps_hdrops++; 525085Swnj goto drop; 535085Swnj } 545085Swnj ti = mtod(m, struct tcpiphdr *); 555085Swnj } 564601Swnj 574601Swnj /* 584924Swnj * Checksum extended tcp header and data. 594601Swnj */ 604924Swnj tlen = ((struct ip *)ti)->ip_len; 614924Swnj len = sizeof (struct ip) + tlen; 624679Swnj if (tcpcksum) { 634924Swnj ti->ti_next = ti->ti_prev = 0; 644924Swnj ti->ti_x1 = 0; 654953Swnj ti->ti_len = htons((u_short)tlen); 665085Swnj if ((ti->ti_sum = in_cksum(m, len)) != 0xffff) { 674924Swnj tcpstat.tcps_badsum++; 685065Swnj printf("tcp cksum %x\n", ti->ti_sum); 695085Swnj goto drop; 704601Swnj } 714601Swnj } 724601Swnj 734601Swnj /* 744924Swnj * Check that tcp offset makes sense, 754924Swnj * process tcp options and adjust length. 764601Swnj */ 774924Swnj off = ti->ti_off << 2; 784924Swnj if (off < sizeof (struct tcphdr) || off > ti->ti_len) { 794924Swnj tcpstat.tcps_badoff++; 805085Swnj goto drop; 814924Swnj } 824924Swnj ti->ti_len = tlen - off; 835085Swnj #if 0 845085Swnj if (off > sizeof (struct tcphdr) >> 2) 855085Swnj tcp_options(ti); 865085Swnj #endif 875065Swnj tiflags = ti->ti_flags; 884924Swnj 894924Swnj /* 905085Swnj * Convert tcp protocol specific fields to host format. 915085Swnj */ 925085Swnj ti->ti_seq = ntohl(ti->ti_seq); 935085Swnj ti->ti_ack = ntohl(ti->ti_ack); 945085Swnj ti->ti_win = ntohs(ti->ti_win); 955085Swnj ti->ti_urp = ntohs(ti->ti_urp); 965085Swnj 975085Swnj /* 984924Swnj * Locate pcb for segment. 994924Swnj */ 1005065Swnj inp = in_pcblookup 1015065Swnj (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport); 1025065Swnj 1035065Swnj /* 1045065Swnj * If the state is CLOSED (i.e., TCB does not exist) then 1055065Swnj * all data in the incoming segment is discarded. (p. 65). 1065065Swnj */ 1074884Swnj if (inp == 0) 1085085Swnj goto dropwithreset; 1095065Swnj tp = intotcpcb(inp); 1105065Swnj if (tp == 0) 1115085Swnj goto dropwithreset; 112*5109Swnj so = inp->inp_socket; 1134601Swnj 1144601Swnj /* 1155085Swnj * Calculate amount of space in receive window, 1165085Swnj * and then do TCP input processing. 1174601Swnj */ 1185085Swnj tp->rcv_wnd = sbspace(&so->so_rcv); 1194601Swnj 1204601Swnj switch (tp->t_state) { 1214601Swnj 1225065Swnj /* 1235065Swnj * If the state is LISTEN then ignore segment if it contains an RST. 1245065Swnj * If the segment contains an ACK then it is bad and send a RST. 1255065Swnj * If it does not contain a SYN then it is not interesting; drop it. 1265085Swnj * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial 1275065Swnj * tp->iss, and send a segment: 1285085Swnj * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> 1295065Swnj * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. 1305065Swnj * Fill in remote peer address fields if not previously specified. 1315065Swnj * Enter SYN_RECEIVED state, and process any other fields of this 1325065Swnj * segment in this state. (p. 65) 1335065Swnj */ 1345065Swnj case TCPS_LISTEN: 1355065Swnj if (tiflags & TH_RST) 1365065Swnj goto drop; 1375065Swnj if (tiflags & TH_ACK) 1385085Swnj goto dropwithreset; 1395065Swnj if ((tiflags & TH_SYN) == 0) 1405065Swnj goto drop; 1415085Swnj tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 1425065Swnj tp->irs = ti->ti_seq; 1435085Swnj tcp_sendseqinit(tp); 1445085Swnj tcp_rcvseqinit(tp); 1455065Swnj tp->t_state = TCPS_SYN_RECEIVED; 1465065Swnj if (inp->inp_faddr.s_addr == 0) { 1475065Swnj inp->inp_faddr = ti->ti_src; 1485065Swnj inp->inp_fport = ti->ti_sport; 1494601Swnj } 1505085Swnj goto trimthenstep6; 1514601Swnj 1525065Swnj /* 1535065Swnj * If the state is SYN_SENT: 1545065Swnj * if seg contains an ACK, but not for our SYN, drop the input. 1555065Swnj * if seg contains a RST, then drop the connection. 1565065Swnj * if seg does not contain SYN, then drop it. 1575065Swnj * Otherwise this is an acceptable SYN segment 1585065Swnj * initialize tp->rcv_nxt and tp->irs 1595065Swnj * if seg contains ack then advance tp->snd_una 1605065Swnj * if SYN has been acked change to ESTABLISHED else SYN_RCVD state 1615065Swnj * arrange for segment to be acked (eventually) 1625065Swnj * continue processing rest of data/controls, beginning with URG 1635065Swnj */ 1645065Swnj case TCPS_SYN_SENT: 1655065Swnj if ((tiflags & TH_ACK) && 1665065Swnj (SEQ_LEQ(ti->ti_ack, tp->iss) || 1675085Swnj SEQ_GT(ti->ti_ack, tp->snd_nxt))) 1685085Swnj goto dropwithreset; 1695065Swnj if (tiflags & TH_RST) { 1705065Swnj if (tiflags & TH_ACK) 1715085Swnj tcp_drop(tp, ECONNRESET); 1725065Swnj goto drop; 1734601Swnj } 1745065Swnj if ((tiflags & TH_SYN) == 0) 1755065Swnj goto drop; 1765085Swnj tp->iss = ti->ti_ack; 1775085Swnj tcp_sendseqinit(tp); 1785065Swnj tp->irs = ti->ti_seq; 1795085Swnj tcp_rcvseqinit(tp); 1805085Swnj tp->t_flags |= TF_ACKNOW; 1815085Swnj if (SEQ_GT(tp->snd_una, tp->iss)) 1825065Swnj tp->t_state = TCPS_ESTABLISHED; 1835085Swnj else 1845085Swnj tp->t_state = TCPS_SYN_RECEIVED; 1855085Swnj goto trimthenstep6; 1865085Swnj 1875085Swnj trimthenstep6: 1885085Swnj /* 1895085Swnj * If had syn, advance ti->ti_seq to correspond 1905085Swnj * to first data byte. 1915085Swnj */ 1925085Swnj if (tiflags & TH_SYN) 1935085Swnj ti->ti_seq++; 1945085Swnj 1955085Swnj /* 1965085Swnj * If data, trim to stay within window, 1975085Swnj * dropping FIN if necessary. 1985085Swnj */ 1995085Swnj if (ti->ti_len > tp->rcv_wnd) { 2005085Swnj todrop = ti->ti_len - tp->rcv_wnd; 2015085Swnj m_adj(m, -todrop); 2025085Swnj ti->ti_len = tp->rcv_wnd; 2035085Swnj ti->ti_flags &= ~TH_FIN; 2045065Swnj } 2055085Swnj goto step6; 2065065Swnj } 2074601Swnj 2085065Swnj /* 2095065Swnj * States other than LISTEN or SYN_SENT. 2105065Swnj * First check that at least some bytes of segment are within 2115065Swnj * receive window. 2125065Swnj */ 2135065Swnj if (tp->rcv_wnd == 0) { 2145065Swnj /* 2155065Swnj * If window is closed can only take segments at 2165065Swnj * window edge, and have to drop data and EOL from 2175065Swnj * incoming segments. 2185065Swnj */ 2195065Swnj if (tp->rcv_nxt != ti->ti_seq) 2205065Swnj goto dropafterack; 2215085Swnj if (ti->ti_len > 0) { 2225085Swnj ti->ti_len = 0; 2235085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 2245065Swnj } 2255065Swnj } else { 2265065Swnj /* 2275065Swnj * If segment begins before rcv_next, drop leading 2285065Swnj * data (and SYN); if nothing left, just ack. 2295065Swnj */ 2305065Swnj if (SEQ_GT(tp->rcv_nxt, ti->ti_seq)) { 2315085Swnj todrop = tp->rcv_nxt - ti->ti_seq; 2325085Swnj if (tiflags & TH_SYN) { 2335085Swnj ti->ti_seq++; 2345085Swnj if (ti->ti_urp > 1) 2355085Swnj ti->ti_urp--; 2365085Swnj else 2375085Swnj tiflags &= ~TH_URG; 2385085Swnj todrop--; 2395085Swnj } 2405065Swnj if (todrop > ti->ti_len) 2415065Swnj goto dropafterack; 2425065Swnj m_adj(m, todrop); 2435065Swnj ti->ti_seq += todrop; 2445065Swnj ti->ti_len -= todrop; 2455085Swnj if (ti->ti_urp > todrop) 2465085Swnj ti->ti_urp -= todrop; 2475085Swnj else { 2485085Swnj tiflags &= ~TH_URG; 2495085Swnj /* ti->ti_flags &= ~TH_URG; */ 2505085Swnj /* ti->ti_urp = 0; */ 2515085Swnj } 2525085Swnj /* tiflags &= ~TH_SYN; */ 2535085Swnj /* ti->ti_flags &= ~TH_SYN; */ 2545065Swnj } 2555065Swnj /* 2565065Swnj * If segment ends after window, drop trailing data 2575085Swnj * (and PUSH and FIN); if nothing left, just ACK. 2585065Swnj */ 2595065Swnj if (SEQ_GT(ti->ti_seq+ti->ti_len, tp->rcv_nxt+tp->rcv_wnd)) { 2605085Swnj todrop = 2615065Swnj ti->ti_seq+ti->ti_len - (tp->rcv_nxt+tp->rcv_wnd); 2625065Swnj if (todrop > ti->ti_len) 2635065Swnj goto dropafterack; 2645065Swnj m_adj(m, -todrop); 2655065Swnj ti->ti_len -= todrop; 2665085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 2675065Swnj } 2685065Swnj } 2694601Swnj 2705065Swnj /* 2715065Swnj * If the RST bit is set examine the state: 2725065Swnj * SYN_RECEIVED STATE: 2735065Swnj * If passive open, return to LISTEN state. 2745065Swnj * If active open, inform user that connection was refused. 2755065Swnj * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: 2765065Swnj * Inform user that connection was reset, and close tcb. 2775065Swnj * CLOSING, LAST_ACK, TIME_WAIT STATES 2785065Swnj * Close the tcb. 2795065Swnj */ 2805065Swnj if (tiflags&TH_RST) switch (tp->t_state) { 2815065Swnj 2825065Swnj case TCPS_SYN_RECEIVED: 2835065Swnj if (inp->inp_socket->so_options & SO_ACCEPTCONN) { 2845085Swnj tp->t_state = TCPS_LISTEN; 2855085Swnj inp->inp_faddr.s_addr = 0; 2865065Swnj goto drop; 2874601Swnj } 2885085Swnj tcp_drop(tp, ECONNREFUSED); 2895065Swnj goto drop; 2904601Swnj 2915065Swnj case TCPS_ESTABLISHED: 2925065Swnj case TCPS_FIN_WAIT_1: 2935065Swnj case TCPS_FIN_WAIT_2: 2945065Swnj case TCPS_CLOSE_WAIT: 2955065Swnj tcp_drop(tp, ECONNRESET); 2965065Swnj goto drop; 2975065Swnj 2985065Swnj case TCPS_CLOSING: 2995065Swnj case TCPS_LAST_ACK: 3005065Swnj case TCPS_TIME_WAIT: 3015065Swnj tcp_close(tp); 3025065Swnj goto drop; 3034601Swnj } 3044601Swnj 3054601Swnj /* 3065065Swnj * If a SYN is in the window, then this is an 3075065Swnj * error and we send an RST and drop the connection. 3084601Swnj */ 3095065Swnj if (tiflags & TH_SYN) { 3105085Swnj tcp_drop(tp, ECONNABORTED); 3115085Swnj goto dropwithreset; 3124601Swnj } 3134601Swnj 3144601Swnj /* 3155065Swnj * If the ACK bit is off we drop the segment and return. 3164601Swnj */ 3175085Swnj if ((tiflags & TH_ACK) == 0) 3185065Swnj goto drop; 3195065Swnj 3205065Swnj /* 3215065Swnj * Ack processing. 3225065Swnj */ 3234601Swnj switch (tp->t_state) { 3244601Swnj 3255065Swnj /* 3265065Swnj * In SYN_RECEIVED state if the ack ACKs our SYN then enter 3275065Swnj * ESTABLISHED state and continue processing, othewise 3285065Swnj * send an RST. 3295065Swnj */ 3305065Swnj case TCPS_SYN_RECEIVED: 3315085Swnj if (SEQ_GT(tp->snd_una, ti->ti_ack) || 3325085Swnj SEQ_GT(ti->ti_ack, tp->snd_nxt)) 3335085Swnj goto dropwithreset; 3345085Swnj soisconnected(so); 3355085Swnj tp->t_state = TCPS_ESTABLISHED; 3365085Swnj /* fall into ... */ 3374601Swnj 3385065Swnj /* 3395065Swnj * In ESTABLISHED state: drop duplicate ACKs; ACK out of range 3405065Swnj * ACKs. If the ack is in the range 3415065Swnj * tp->snd_una < ti->ti_ack <= tp->snd_nxt 3425065Swnj * then advance tp->snd_una to ti->ti_ack and drop 3435065Swnj * data from the retransmission queue. If this ACK reflects 3445065Swnj * more up to date window information we update our window information. 3455065Swnj */ 3465065Swnj case TCPS_ESTABLISHED: 3475065Swnj case TCPS_FIN_WAIT_1: 3485065Swnj case TCPS_FIN_WAIT_2: 3495065Swnj case TCPS_CLOSE_WAIT: 3505065Swnj case TCPS_CLOSING: 3515085Swnj #define ourfinisacked (acked > 0) 3525085Swnj 3535065Swnj if (SEQ_LT(ti->ti_ack, tp->snd_una)) 3545065Swnj break; 3555065Swnj if (SEQ_GT(ti->ti_ack, tp->snd_nxt)) 3565065Swnj goto dropafterack; 3575085Swnj acked = ti->ti_ack - tp->snd_una; 3585085Swnj if (acked > so->so_snd.sb_cc) { 3595085Swnj sbflush(&so->so_snd); 3605085Swnj acked -= so->so_snd.sb_cc; 3615085Swnj } else { 3625085Swnj sbdrop(&so->so_snd, acked); 3635085Swnj acked = 0; 3645085Swnj } 3655085Swnj /* if acked our FIN is acked */ 3665065Swnj tp->snd_una = ti->ti_ack; 3675085Swnj 3685085Swnj /* 3695085Swnj * Update window information. 3705085Swnj */ 3715065Swnj if (SEQ_LT(tp->snd_wl1, ti->ti_seq) || 3725085Swnj tp->snd_wl1==ti->ti_seq && SEQ_LEQ(tp->snd_wl2,ti->ti_seq)) { 3735065Swnj tp->snd_wnd = ti->ti_win; 3745065Swnj tp->snd_wl1 = ti->ti_seq; 3755065Swnj tp->snd_wl2 = ti->ti_ack; 3764601Swnj } 3774601Swnj 3784601Swnj switch (tp->t_state) { 3794601Swnj 3805065Swnj /* 3815065Swnj * In FIN_WAIT_1 STATE in addition to the processing 3825065Swnj * for the ESTABLISHED state if our FIN is now acknowledged 3835085Swnj * then enter FIN_WAIT_2. 3845065Swnj */ 3855065Swnj case TCPS_FIN_WAIT_1: 3865085Swnj if (ourfinisacked) 3875085Swnj tp->t_state = TCPS_FIN_WAIT_2; 3884601Swnj break; 3894601Swnj 3905065Swnj /* 3915065Swnj * In CLOSING STATE in addition to the processing for 3925065Swnj * the ESTABLISHED state if the ACK acknowledges our FIN 3935065Swnj * then enter the TIME-WAIT state, otherwise ignore 3945065Swnj * the segment. 3955065Swnj */ 3965065Swnj case TCPS_CLOSING: 3975085Swnj if (ourfinisacked) 3985065Swnj tp->t_state = TCPS_TIME_WAIT; 3995085Swnj goto drop; 4004601Swnj 4015065Swnj /* 4025085Swnj * The only thing that can arrive in LAST_ACK state 4035085Swnj * is an acknowledgment of our FIN. If our FIN is now 4045085Swnj * acknowledged, delete the TCB, enter the closed state 4055085Swnj * and return. 4065065Swnj */ 4075065Swnj case TCPS_LAST_ACK: 4085085Swnj if (ourfinisacked) 4095065Swnj tcp_close(tp); 4105065Swnj goto drop; 4114601Swnj 4125065Swnj /* 4135065Swnj * In TIME_WAIT state the only thing that should arrive 4145065Swnj * is a retransmission of the remote FIN. Acknowledge 4155065Swnj * it and restart the finack timer. 4165065Swnj */ 4175065Swnj case TCPS_TIME_WAIT: 4185085Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPSC_MSL; 4195065Swnj goto dropafterack; 4204601Swnj } 4215085Swnj #undef ourfinisacked 4225085Swnj } 4234601Swnj 4245065Swnj step6: 4255065Swnj /* 4265065Swnj * If an URG bit is set in the segment and is greater than the 4275065Swnj * current known urgent pointer, then signal the user that the 4285065Swnj * remote side has urgent data. This should not happen 4295065Swnj * in CLOSE_WAIT, CLOSING, LAST-ACK or TIME_WAIT STATES since 4305065Swnj * a FIN has been received from the remote side. In these states 4315065Swnj * we ignore the URG. 4325065Swnj */ 4335085Swnj if ((tiflags & TH_URG) == 0 && TCPS_HAVERCVDFIN(tp->t_state) == 0) 4345085Swnj if (SEQ_GT(ti->ti_urp, tp->rcv_up)) { 4355065Swnj tp->rcv_up = ti->ti_urp; 4365085Swnj #if 0 4375065Swnj soisurgendata(so); /* XXX */ 4385085Swnj #endif 4394601Swnj } 4404601Swnj 4414601Swnj /* 4425065Swnj * Process the segment text, merging it into the TCP sequencing queue, 4435065Swnj * and arranging for acknowledgment of receipt if necessary. 4445065Swnj * This process logically involves adjusting tp->rcv_wnd as data 4455065Swnj * is presented to the user (this happens in tcp_usrreq.c, 4465065Swnj * case PRU_RCVD). If a FIN has already been received on this 4475065Swnj * connection then we just ignore the text. 4484601Swnj */ 4495065Swnj if (ti->ti_len) { 4505085Swnj if (TCPS_HAVERCVDFIN(tp->t_state)) 4515065Swnj goto drop; 4525085Swnj off += sizeof (struct ip); /* drop IP header */ 4535085Swnj m->m_off += off; 4545085Swnj m->m_len -= off; 4555065Swnj tiflags = tcp_reass(tp, ti); 4565085Swnj tp->t_flags |= TF_ACKNOW; /* XXX TF_DELACK */ 4575085Swnj } else 4584924Swnj m_freem(m); 4594601Swnj 4604601Swnj /* 4615065Swnj * If FIN is received then if we haven't received SYN and 4625065Swnj * therefore can't validate drop the segment. Otherwise ACK 4635065Swnj * the FIN and let the user know that the connection is closing. 4644601Swnj */ 4655085Swnj if ((tiflags & TH_FIN)) { 4665074Swnj if (TCPS_HAVERCVDSYN(tp->t_state) == 0) 4675074Swnj goto drop; 4685074Swnj socantrcvmore(so); 4695065Swnj tp->t_flags |= TF_ACKNOW; 4705065Swnj tp->rcv_nxt++; 4715065Swnj switch (tp->t_state) { 4724601Swnj 4735065Swnj /* 4745065Swnj * In SYN_RECEIVED and ESTABLISHED STATES 4755065Swnj * enter the CLOSE_WAIT state. 4764884Swnj */ 4775065Swnj case TCPS_SYN_RECEIVED: 4785065Swnj case TCPS_ESTABLISHED: 4795065Swnj tp->t_state = TCPS_CLOSE_WAIT; 4805065Swnj break; 4814884Swnj 4825065Swnj /* 4835085Swnj * If still in FIN_WAIT_1 STATE FIN has not been acked so 4845085Swnj * enter the CLOSING state. 4854884Swnj */ 4865065Swnj case TCPS_FIN_WAIT_1: 4875085Swnj tp->t_state = TCPS_CLOSING; 4885065Swnj break; 4894601Swnj 4905065Swnj /* 4915065Swnj * In FIN_WAIT_2 state enter the TIME_WAIT state, 4925065Swnj * starting the time-wait timer, turning off the other 4935065Swnj * standard timers. 4945065Swnj */ 4955065Swnj case TCPS_FIN_WAIT_2: 4965085Swnj tp->t_state = TCPS_TIME_WAIT;; 4975074Swnj tcp_canceltimers(tp); 4985085Swnj tp->t_timer[TCPT_2MSL] = TCPSC_2MSL; 4995065Swnj break; 5005065Swnj 5014884Swnj /* 5025065Swnj * In TIME_WAIT state restart the 2 MSL time_wait timer. 5034884Swnj */ 5045065Swnj case TCPS_TIME_WAIT: 5055085Swnj tp->t_timer[TCPT_2MSL] = TCPSC_2MSL; 5065065Swnj break; 5075085Swnj } 5084601Swnj } 5095085Swnj 5105085Swnj /* 5115085Swnj * Return any desired output. 5125085Swnj */ 5135085Swnj tcp_output(tp); 5145065Swnj return; 5155085Swnj 5165065Swnj dropafterack: 5175085Swnj /* 5185085Swnj * Generate an ACK, then drop incoming segment. 5195085Swnj * Make ACK reflect our state. 5205085Swnj */ 5215085Swnj if (tiflags & TH_RST) 5225085Swnj goto drop; 5235085Swnj tcp_respond(ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK); 5245085Swnj goto drop; 5255085Swnj 5265085Swnj dropwithreset: 5275085Swnj /* 5285085Swnj * Generate a RST, then drop incoming segment. 5295085Swnj * Make ACK acceptable to originator of segment. 5305085Swnj */ 5315085Swnj if (tiflags & TH_RST) 5325085Swnj goto drop; 5335085Swnj if (tiflags & TH_ACK) 534*5109Swnj tcp_respond(ti, (tcp_seq)0, ti->ti_ack, TH_RST); 5355085Swnj else { 5365085Swnj if (tiflags & TH_SYN) 5375085Swnj ti->ti_len++; 538*5109Swnj tcp_respond(ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK); 5395085Swnj } 5405085Swnj goto drop; 5415085Swnj 5425065Swnj drop: 5435085Swnj /* 5445085Swnj * Drop space held by incoming segment and return. 5455085Swnj */ 5465065Swnj m_freem(m); 5475065Swnj } 5485065Swnj 5495065Swnj /* 5505065Swnj * Insert segment ti into reassembly queue of tcp with 5515065Swnj * control block tp. Return TH_FIN if reassembly now includes 5525065Swnj * a segment with FIN. 5535065Swnj */ 554*5109Swnj tcp_reass(tp, ti) 5555065Swnj register struct tcpcb *tp; 5565065Swnj register struct tcpiphdr *ti; 5575065Swnj { 5585065Swnj register struct tcpiphdr *q; 5595085Swnj struct socket *so = tp->t_inpcb->inp_socket; 5605065Swnj int flags = 0; /* no FIN */ 5615065Swnj int overage; 5625085Swnj COUNT(TCP_REASS); 5635065Swnj 5645065Swnj /* 5655065Swnj * If no data in this segment may want 5665065Swnj * to move data up to socket structure (if 5675065Swnj * connection is now established). 5685065Swnj */ 5695065Swnj if (ti->ti_len == 0) { 5705065Swnj m_freem(dtom(ti)); 5715065Swnj goto present; 5724601Swnj } 5734601Swnj 5745065Swnj /* 5755065Swnj * Find a segment which begins after this one does. 5765065Swnj */ 5775065Swnj for (q = tp->seg_next; q != (struct tcpiphdr *)tp; 5785065Swnj q = (struct tcpiphdr *)q->ti_next) 5795065Swnj if (SEQ_GT(q->ti_seq, ti->ti_seq)) 5805065Swnj break; 5814601Swnj 5825065Swnj /* 5835065Swnj * If there is a preceding segment, it may provide some of 5845065Swnj * our data already. If so, drop the data from the incoming 5855065Swnj * segment. If it provides all of our data, drop us. 5865065Swnj */ 5875065Swnj if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { 5885065Swnj register int i; 5895065Swnj q = (struct tcpiphdr *)(q->ti_prev); 5905065Swnj /* conversion to int (in i) handles seq wraparound */ 5915065Swnj i = q->ti_seq + q->ti_len - ti->ti_seq; 5925065Swnj if (i > 0) { 5934924Swnj if (i >= ti->ti_len) 5945065Swnj goto drop; 5955065Swnj m_adj(dtom(tp), i); 5965065Swnj ti->ti_len -= i; 5974924Swnj ti->ti_seq += i; 5984601Swnj } 5995065Swnj q = (struct tcpiphdr *)(q->ti_next); 6005065Swnj } 6014601Swnj 6025065Swnj /* 6035065Swnj * While we overlap succeeding segments trim them or, 6045065Swnj * if they are completely covered, dequeue them. 6055065Swnj */ 6065065Swnj while (q != (struct tcpiphdr *)tp && 6075065Swnj SEQ_GT(ti->ti_seq + ti->ti_len, q->ti_seq)) { 6085065Swnj register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; 6095065Swnj if (i < q->ti_len) { 6105065Swnj q->ti_len -= i; 6115065Swnj m_adj(dtom(q), i); 6125065Swnj break; 6134601Swnj } 6145065Swnj q = (struct tcpiphdr *)q->ti_next; 6155065Swnj m_freem(dtom(q->ti_prev)); 6165065Swnj remque(q->ti_prev); 6175065Swnj } 6184601Swnj 6195065Swnj /* 6205065Swnj * Stick new segment in its place. 6215065Swnj */ 6225065Swnj insque(ti, q->ti_prev); 6235085Swnj tp->t_seqcnt += ti->ti_len; 6244601Swnj 6255065Swnj /* 6265065Swnj * Calculate available space and discard segments for 6275065Swnj * which there is too much. 6285065Swnj */ 6295065Swnj overage = 6305085Swnj (so->so_rcv.sb_cc + tp->t_seqcnt) - so->so_rcv.sb_hiwat; 6315065Swnj if (overage > 0) { 6325065Swnj q = tp->seg_prev; 6335065Swnj for (;;) { 6345065Swnj register int i = MIN(q->ti_len, overage); 6355065Swnj overage -= i; 6365085Swnj tp->t_seqcnt -= i; 6375065Swnj q->ti_len -= i; 6385065Swnj m_adj(dtom(q), -i); 6395065Swnj if (q->ti_len) 6404645Swnj break; 6415065Swnj if (q == ti) 6425074Swnj panic("tcp_reass dropall"); 6435065Swnj q = (struct tcpiphdr *)q->ti_prev; 6445065Swnj remque(q->ti_next); 6454645Swnj } 6464884Swnj } 6475065Swnj 6485065Swnj /* 6495065Swnj * Advance rcv_next through newly completed sequence space. 6505065Swnj */ 6515065Swnj while (ti->ti_seq == tp->rcv_nxt) { 6525065Swnj tp->rcv_nxt += ti->ti_len; 6535065Swnj flags = ti->ti_flags & TH_FIN; 6545065Swnj ti = (struct tcpiphdr *)ti->ti_next; 6555065Swnj if (ti == (struct tcpiphdr *)tp) 6565065Swnj break; 6574679Swnj } 6584679Swnj 6595065Swnj present: 6605065Swnj /* 6615065Swnj * Present data to user. 6625065Swnj */ 6635085Swnj if (tp->t_state < TCPS_ESTABLISHED) 6645065Swnj return (flags); 6654924Swnj ti = tp->seg_next; 6664924Swnj while (ti != (struct tcpiphdr *)tp && ti->ti_seq < tp->rcv_nxt) { 6674924Swnj remque(ti); 6684924Swnj sbappend(&so->so_rcv, dtom(ti)); 6695085Swnj tp->t_seqcnt -= ti->ti_len; 6705085Swnj if (tp->t_seqcnt < 0) 6715065Swnj panic("tcp_reass"); 6724924Swnj ti = (struct tcpiphdr *)ti->ti_next; 6734601Swnj } 6745074Swnj if (so->so_state & SS_CANTRCVMORE) 6755074Swnj sbflush(&so->so_rcv); 6765074Swnj else 6775074Swnj sorwakeup(so); 6785065Swnj return (flags); 6795065Swnj drop: 6805065Swnj m_freem(dtom(ti)); 6815065Swnj return (flags); 6824601Swnj } 683