1*5074Swnj /* tcp_input.c 1.31 81/11/25 */ 24601Swnj 34601Swnj #include "../h/param.h" 44601Swnj #include "../h/systm.h" 54663Swnj #include "../h/mbuf.h" 64663Swnj #include "../h/socket.h" 74803Swnj #include "../h/socketvar.h" 84803Swnj #include "../net/inet.h" 94884Swnj #include "../net/inet_pcb.h" 104803Swnj #include "../net/inet_systm.h" 114803Swnj #include "../net/imp.h" 124803Swnj #include "../net/ip.h" 134899Swnj #include "../net/ip_var.h" 144803Swnj #include "../net/tcp.h" 154803Swnj #include "../net/tcp_fsm.h" 164803Swnj #include "../net/tcp_var.h" 174803Swnj #include "/usr/include/errno.h" 184601Swnj 194679Swnj int tcpcksum = 1; 204601Swnj 214953Swnj struct sockaddr_in tcp_sockaddr = { AF_INET }; 224953Swnj 235065Swnj /* 245065Swnj * TCP input routine, follows pages 65-76 of the 255065Swnj * protocol specification dated September, 1981 very closely. 265065Swnj */ 274924Swnj tcp_input(m0) 284924Swnj struct mbuf *m0; 294601Swnj { 304924Swnj register struct tcpiphdr *ti; 314924Swnj struct inpcb *inp; 324924Swnj register struct mbuf *m; 334924Swnj int len, tlen, off; 344924Swnj register struct tcpcb *tp; 354924Swnj register int tiflags; 364803Swnj struct socket *so; 375065Swnj seq_t segend; 385065Swnj int acceptable; 394924Swnj 404601Swnj COUNT(TCP_INPUT); 414924Swnj /* 424924Swnj * Get ip and tcp header together in first mbuf. 434924Swnj */ 444924Swnj m = m0; 454924Swnj if (m->m_len < sizeof (struct tcpiphdr) && 464924Swnj m_pullup(m, sizeof (struct tcpiphdr)) == 0) { 474924Swnj tcpstat.tcps_hdrops++; 484924Swnj goto bad; 494924Swnj } 505020Sroot ti = mtod(m, struct tcpiphdr *); 515020Sroot if (ti->ti_len > sizeof (struct ip)) 525020Sroot ip_stripoptions((struct ip *)ti, (char *)0); 534601Swnj 544601Swnj /* 554924Swnj * Checksum extended tcp header and data. 564601Swnj */ 574924Swnj tlen = ((struct ip *)ti)->ip_len; 584924Swnj len = sizeof (struct ip) + tlen; 594679Swnj if (tcpcksum) { 604924Swnj ti->ti_next = ti->ti_prev = 0; 614924Swnj ti->ti_x1 = 0; 624953Swnj ti->ti_len = htons((u_short)tlen); 635048Swnj if ((ti->ti_sum = inet_cksum(m, len)) != 0xffff) { 644924Swnj tcpstat.tcps_badsum++; 655065Swnj printf("tcp cksum %x\n", ti->ti_sum); 664924Swnj goto bad; 674601Swnj } 684601Swnj } 694601Swnj 704601Swnj /* 714924Swnj * Check that tcp offset makes sense, 724924Swnj * process tcp options and adjust length. 734601Swnj */ 744924Swnj off = ti->ti_off << 2; 754924Swnj if (off < sizeof (struct tcphdr) || off > ti->ti_len) { 764924Swnj tcpstat.tcps_badoff++; 774924Swnj goto bad; 784924Swnj } 794924Swnj ti->ti_len = tlen - off; 804924Swnj /* PROCESS OPTIONS */ 815065Swnj tiflags = ti->ti_flags; 824924Swnj 834924Swnj /* 844924Swnj * Locate pcb for segment. 854924Swnj */ 865065Swnj inp = in_pcblookup 875065Swnj (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport); 885065Swnj 895065Swnj /* 905065Swnj * If the state is CLOSED (i.e., TCB does not exist) then 915065Swnj * all data in the incoming segment is discarded. (p. 65). 925065Swnj */ 934884Swnj if (inp == 0) 945065Swnj goto sendreset; 955065Swnj tp = intotcpcb(inp); 965065Swnj if (tp == 0) 975065Swnj goto sendreset; 984601Swnj 994601Swnj /* 1004924Swnj * Convert tcp protocol specific fields to host format. 1014601Swnj */ 1024924Swnj ti->ti_seq = ntohl(ti->ti_seq); 1034924Swnj ti->ti_ackno = ntohl((n_long)ti->ti_ackno); 1044924Swnj ti->ti_win = ntohs(ti->ti_win); 1054924Swnj ti->ti_urp = ntohs(ti->ti_urp); 1064601Swnj 1074601Swnj /* 1085065Swnj * Discard ip header, and do tcp input processing. 1094601Swnj */ 1105065Swnj off += sizeof (struct ip); 1115065Swnj m->m_off += off; 1125065Swnj m->m_len -= off; 1135065Swnj 1144601Swnj switch (tp->t_state) { 1154601Swnj 1165065Swnj /* 1175065Swnj * If the state is LISTEN then ignore segment if it contains an RST. 1185065Swnj * If the segment contains an ACK then it is bad and send a RST. 1195065Swnj * If it does not contain a SYN then it is not interesting; drop it. 1205065Swnj * Otherwise initialize tp->rcv_next, and tp->irs, select an initial 1215065Swnj * tp->iss, and send a segment: 1225065Swnj * <SEQ=ISS><ACK=RCV>NXT><CTL=SYN,ACK> 1235065Swnj * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. 1245065Swnj * Fill in remote peer address fields if not previously specified. 1255065Swnj * Enter SYN_RECEIVED state, and process any other fields of this 1265065Swnj * segment in this state. (p. 65) 1275065Swnj */ 1285065Swnj case TCPS_LISTEN: 1295065Swnj if (tiflags & TH_RST) 1305065Swnj goto drop; 1315065Swnj if (tiflags & TH_ACK) 1325065Swnj goto sendrst; 1335065Swnj if ((tiflags & TH_SYN) == 0) 1345065Swnj goto drop; 1355065Swnj tp->rcv_nxt = ti->ti_seq + 1; 1365065Swnj tp->irs = ti->ti_seq; 1375065Swnj tp->iss = tcp_selectiss(); 1385065Swnj tcp_reflect(ti, tp->iss, tp->rcv_next, TH_SYN|TH_ACK); 1395065Swnj tp->t_state = TCPS_SYN_RECEIVED; 1405065Swnj tiflags &= ~TH_SYN; tiflags |= TH_RST; 1415065Swnj if (inp->inp_faddr.s_addr == 0) { 1425065Swnj inp->inp_faddr = ti->ti_src; 1435065Swnj inp->inp_fport = ti->ti_sport; 1444601Swnj } 1455065Swnj break; 1464601Swnj 1475065Swnj /* 1485065Swnj * If the state is SYN_SENT: 1495065Swnj * if seg contains an ACK, but not for our SYN, drop the input. 1505065Swnj * if seg contains a RST, then drop the connection. 1515065Swnj * if seg does not contain SYN, then drop it. 1525065Swnj * Otherwise this is an acceptable SYN segment 1535065Swnj * initialize tp->rcv_nxt and tp->irs 1545065Swnj * if seg contains ack then advance tp->snd_una 1555065Swnj * if SYN has been acked change to ESTABLISHED else SYN_RCVD state 1565065Swnj * arrange for segment to be acked (eventually) 1575065Swnj * continue processing rest of data/controls, beginning with URG 1585065Swnj */ 1595065Swnj case TCPS_SYN_SENT: 1605065Swnj if ((tiflags & TH_ACK) && 1615065Swnj (SEQ_LEQ(ti->ti_ack, tp->iss) || 1625065Swnj SEQ_GT(ti->ti_ack, tp->snd.nxt))) { 1635065Swnj tcp_reflect(ti, ti->ti_ack, 0, TH_RST); 1645065Swnj goto drop; 1654601Swnj } 1665065Swnj if (tiflags & TH_RST) { 1675065Swnj if (tiflags & TH_ACK) 1685065Swnj tcp_drop(tp, ENETRESET); 1695065Swnj goto drop; 1704601Swnj } 1715065Swnj if ((tiflags & TH_SYN) == 0) 1725065Swnj goto drop; 1735065Swnj tp->rcv_nxt = ti->ti_seq + 1; 1745065Swnj tp->irs = ti->ti_seq; 1755065Swnj tp->snd_una = ti->ti_seq; 1765065Swnj if (SEQ_GT(tp->snd_una, tp->iss)) { 1775065Swnj tp->t_state = TCPS_ESTABLISHED; 1785065Swnj tp->t_flags |= TF_OWEACK; 1795065Swnj goto step6; 1805065Swnj } 1815065Swnj tp->t_state = TCPS_SYN_RECEIVED; 1825065Swnj tcp_reflect(ti, tp->iss, tp->rcv_nxt, TH_SYN|TH_ACK); 1835065Swnj break; 1845065Swnj } 1854601Swnj 1865065Swnj /* 1875065Swnj * States other than LISTEN or SYN_SENT. 1885065Swnj * First check that at least some bytes of segment are within 1895065Swnj * receive window. 1905065Swnj */ 1915065Swnj if (tp->rcv_wnd == 0) { 1925065Swnj /* 1935065Swnj * If window is closed can only take segments at 1945065Swnj * window edge, and have to drop data and EOL from 1955065Swnj * incoming segments. 1965065Swnj */ 1975065Swnj if (tp->rcv_nxt != ti->ti_seq) 1985065Swnj goto dropafterack; 1995065Swnj if (tp->ti_len > 0) { 2005065Swnj tp->ti_len = 0; 2015065Swnj tp->ti_flags &= ~(TH_EOL|TH_FIN); 2025065Swnj } 2035065Swnj } else { 2045065Swnj /* 2055065Swnj * If segment begins before rcv_next, drop leading 2065065Swnj * data (and SYN); if nothing left, just ack. 2075065Swnj */ 2085065Swnj if (SEQ_GT(tp->rcv_nxt, ti->ti_seq)) { 2095065Swnj tcpseq_t todrop = tp->rcv_nxt - ti->ti_seq; 2105065Swnj if (todrop > ti->ti_len) 2115065Swnj goto dropafterack; 2125065Swnj m_adj(m, todrop); 2135065Swnj ti->ti_seq += todrop; 2145065Swnj ti->ti_len -= todrop; 2155065Swnj ti->ti_flags &= ~TH_SYN; 2165065Swnj } 2175065Swnj /* 2185065Swnj * If segment ends after window, drop trailing data 2195065Swnj * (and EOL and FIN); if there would be nothing left, just ack. 2205065Swnj */ 2215065Swnj if (SEQ_GT(ti->ti_seq+ti->ti_len, tp->rcv_nxt+tp->rcv_wnd)) { 2225065Swnj tcpseq_t todrop = 2235065Swnj ti->ti_seq+ti->ti_len - (tp->rcv_nxt+tp->rcv_wnd); 2245065Swnj if (todrop > ti->ti_len) 2255065Swnj goto dropafterack; 2265065Swnj m_adj(m, -todrop); 2275065Swnj ti->ti_len -= todrop; 2285065Swnj ti->ti_flags &= ~(TH_EOL|TH_FIN); 2295065Swnj } 2305065Swnj } 2314601Swnj 2325065Swnj /* 2335065Swnj * If the RST bit is set examine the state: 2345065Swnj * SYN_RECEIVED STATE: 2355065Swnj * If passive open, return to LISTEN state. 2365065Swnj * If active open, inform user that connection was refused. 2375065Swnj * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: 2385065Swnj * Inform user that connection was reset, and close tcb. 2395065Swnj * CLOSING, LAST_ACK, TIME_WAIT STATES 2405065Swnj * Close the tcb. 2415065Swnj */ 2425065Swnj if (tiflags&TH_RST) switch (tp->t_state) { 2435065Swnj 2445065Swnj case TCPS_SYN_RECEIVED: 2455065Swnj if (inp->inp_socket->so_options & SO_ACCEPTCONN) { 2464601Swnj tp->t_state = LISTEN; 2475065Swnj inp->inp_fhost->s_addr = 0; 2485065Swnj goto drop; 2494601Swnj } 2505065Swnj tcp_drop(tp, EREFUSED); 2515065Swnj goto drop; 2524601Swnj 2535065Swnj case TCPS_ESTABLISHED: 2545065Swnj case TCPS_FIN_WAIT_1: 2555065Swnj case TCPS_FIN_WAIT_2: 2565065Swnj case TCPS_CLOSE_WAIT: 2575065Swnj tcp_drop(tp, ECONNRESET); 2585065Swnj goto drop; 2595065Swnj 2605065Swnj case TCPS_CLOSING: 2615065Swnj case TCPS_LAST_ACK: 2625065Swnj case TCPS_TIME_WAIT: 2635065Swnj tcp_close(tp); 2645065Swnj goto drop; 2654601Swnj } 2664601Swnj 2674601Swnj /* 2685065Swnj * If a SYN is in the window, then this is an 2695065Swnj * error and we send an RST and drop the connection. 2704601Swnj */ 2715065Swnj if (tiflags & TH_SYN) { 2725065Swnj tcp_drop(tp, ECONNRESET); 2735065Swnj goto sendreset; 2744601Swnj } 2754601Swnj 2764601Swnj /* 2775065Swnj * If the ACK bit is off we drop the segment and return. 2784601Swnj */ 2795065Swnj if ((tiflags & TI_ACK) == 0) 2805065Swnj goto drop; 2815065Swnj 2825065Swnj /* 2835065Swnj * Ack processing. 2845065Swnj */ 2854601Swnj switch (tp->t_state) { 2864601Swnj 2875065Swnj /* 2885065Swnj * In SYN_RECEIVED state if the ack ACKs our SYN then enter 2895065Swnj * ESTABLISHED state and continue processing, othewise 2905065Swnj * send an RST. 2915065Swnj */ 2925065Swnj case TCPS_SYN_RECEIVED: 2935065Swnj if (SEQ_LEQ(tp->snd_una, ti->ti_ack) && 2945065Swnj SEQ_LEQ(ti->ti_ack, tp->snd_nxt)) 2955065Swnj tp->t_state = TCPS_ESTABLISHED; 2965065Swnj else 2975065Swnj goto sendreset; 2985065Swnj /* fall into next case, below... */ 2994601Swnj 3005065Swnj /* 3015065Swnj * In ESTABLISHED state: drop duplicate ACKs; ACK out of range 3025065Swnj * ACKs. If the ack is in the range 3035065Swnj * tp->snd_una < ti->ti_ack <= tp->snd_nxt 3045065Swnj * then advance tp->snd_una to ti->ti_ack and drop 3055065Swnj * data from the retransmission queue. If this ACK reflects 3065065Swnj * more up to date window information we update our window information. 3075065Swnj */ 3085065Swnj case TCPS_ESTABLISHED: 3095065Swnj case TCPS_FIN_WAIT_1: 3105065Swnj case TCPS_FIN_WAIT_2: 3115065Swnj case TCPS_CLOSE_WAIT: 3125065Swnj case TCPS_CLOSING: 3135065Swnj if (SEQ_LT(ti->ti_ack, tp->snd_una)) 3145065Swnj break; 3155065Swnj if (SEQ_GT(ti->ti_ack, tp->snd_nxt)) 3165065Swnj goto dropafterack; 3175065Swnj sbdrop(&so->so_snd, ti->ti_ack - tp->snd_una); 3185065Swnj tp->snd_una = ti->ti_ack; 3195065Swnj if (SEQ_LT(tp->snd_wl1, ti->ti_seq) || 3205065Swnj tp->snd_wl1==ti-ti_seq && SEQ_LEQ(tp->snd_wl2,ti->ti_seq)) { 3215065Swnj tp->snd_wnd = ti->ti_win; 3225065Swnj tp->snd_wl1 = ti->ti_seq; 3235065Swnj tp->snd_wl2 = ti->ti_ack; 3244601Swnj } 3254601Swnj 3264601Swnj switch (tp->t_state) { 3274601Swnj 3285065Swnj /* 3295065Swnj * In FIN_WAIT_1 STATE in addition to the processing 3305065Swnj * for the ESTABLISHED state if our FIN is now acknowledged 3315065Swnj * then enter FIN_WAIT_2 and continue processing in that state. 3325065Swnj */ 3335065Swnj case TCPS_FIN_WAIT_1: 3345065Swnj if (tcp_finisacked(tp) == 0) 3355065Swnj break; 3365065Swnj tp->t_state = TCPS_FIN_WAIT_2; 3375065Swnj /* fall into ... */ 3384601Swnj 3395065Swnj /* 3405065Swnj * In FIN_WAIT_2 STATE in addition to the processing for 3415065Swnj * the ESTABLISHED state allow the user to close when 3425065Swnj * the data has drained. 3435065Swnj */ 3445065Swnj case TCPS_FIN_WAIT_2: 3455065Swnj tcp_usrcanclose(tp); 3464601Swnj break; 3474601Swnj 3485065Swnj /* 3495065Swnj * In CLOSING STATE in addition to the processing for 3505065Swnj * the ESTABLISHED state if the ACK acknowledges our FIN 3515065Swnj * then enter the TIME-WAIT state, otherwise ignore 3525065Swnj * the segment. 3535065Swnj */ 3545065Swnj case TCPS_CLOSING: 3555065Swnj if (tcp_finisacked(tp)) 3565065Swnj tp->t_state = TCPS_TIME_WAIT; 3574601Swnj break; 3584601Swnj 3595065Swnj /* 3605065Swnj * In LAST_ACK state if our FIN is now acknowledged 3615065Swnj * then enter the TIME_WAIT state, otherwise ignore the 3625065Swnj * segment. 3635065Swnj */ 3645065Swnj case TCPS_LAST_ACK: 3655065Swnj if (tcp_finisacked(tp)) 3665065Swnj tcp_close(tp); 3675065Swnj goto drop; 3684601Swnj 3695065Swnj /* 3705065Swnj * In TIME_WAIT state the only thing that should arrive 3715065Swnj * is a retransmission of the remote FIN. Acknowledge 3725065Swnj * it and restart the finack timer. 3735065Swnj */ 3745065Swnj case TCPS_TIME_WAIT: 3755065Swnj tp->t_finack = 2 * TCP_MSL; 3765065Swnj goto dropafterack; 3774601Swnj } 3784601Swnj 3795065Swnj step6: 3805065Swnj /* 3815065Swnj * If an URG bit is set in the segment and is greater than the 3825065Swnj * current known urgent pointer, then signal the user that the 3835065Swnj * remote side has urgent data. This should not happen 3845065Swnj * in CLOSE_WAIT, CLOSING, LAST-ACK or TIME_WAIT STATES since 3855065Swnj * a FIN has been received from the remote side. In these states 3865065Swnj * we ignore the URG. 3875065Swnj */ 3885065Swnj if ((tiflags & TH_URG) == 0 && (TCPS_RCVDFIN(tp->t_state) == 0) { 3895065Swnj if (SEQ_GT(ti->ti_urp, tp->rcv_up) { 3905065Swnj tp->rcv_up = ti->ti_urp; 3915065Swnj soisurgendata(so); /* XXX */ 3924601Swnj } 3934601Swnj } 3944601Swnj 3954601Swnj /* 3965065Swnj * Process the segment text, merging it into the TCP sequencing queue, 3975065Swnj * and arranging for acknowledgment of receipt if necessary. 3985065Swnj * This process logically involves adjusting tp->rcv_wnd as data 3995065Swnj * is presented to the user (this happens in tcp_usrreq.c, 4005065Swnj * case PRU_RCVD). If a FIN has already been received on this 4015065Swnj * connection then we just ignore the text. 4024601Swnj */ 4035065Swnj if (ti->ti_len) { 4045065Swnj if (TCPS_RCVDFIN(tp->t_state)) 4055065Swnj goto drop; 4065065Swnj tiflags = tcp_reass(tp, ti); 4075065Swnj else 4084924Swnj m_freem(m); 4094601Swnj 4104601Swnj /* 4115065Swnj * If FIN is received then if we haven't received SYN and 4125065Swnj * therefore can't validate drop the segment. Otherwise ACK 4135065Swnj * the FIN and let the user know that the connection is closing. 4144601Swnj */ 415*5074Swnj if (tiflags & TH_FIN) { 416*5074Swnj if (TCPS_HAVERCVDSYN(tp->t_state) == 0) 417*5074Swnj goto drop; 418*5074Swnj socantrcvmore(so); 4195065Swnj tp->t_flags |= TF_ACKNOW; 4205065Swnj tp->rcv_nxt++; 4215065Swnj switch (tp->t_state) { 4224601Swnj 4235065Swnj /* 4245065Swnj * In SYN_RECEIVED and ESTABLISHED STATES 4255065Swnj * enter the CLOSE_WAIT state. 4264884Swnj */ 4275065Swnj case TCPS_SYN_RECEIVED: 4285065Swnj case TCPS_ESTABLISHED: 4295065Swnj tp->t_state = TCPS_CLOSE_WAIT; 4305065Swnj break; 4314884Swnj 4325065Swnj /* 4335065Swnj * In FIN_WAIT_1 STATE if our FIN has been acked then 4345065Swnj * enter TIME_WAIT state, starting the associated timer 4355065Swnj * and turning off all other standard timers. 4365065Swnj * If FIN has not been acked enter the CLOSING state. 4374884Swnj */ 4385065Swnj case TCPS_FIN_WAIT_1: 4395065Swnj if (tcp_finisacked(tp)) { 4405065Swnj tp->t_state = TCPS_TIME_WAIT; 4415065Swnj tcp_canceltimers(tp, 0); 4425065Swnj tp->t_timer[TCPT_FINACK] = TCPSC_2MSL; 4435065Swnj } else 4445065Swnj tp->t_state = TCPS_CLOSING; 4455065Swnj break; 4464601Swnj } 4474601Swnj 4485065Swnj /* 4495065Swnj * In FIN_WAIT_2 state enter the TIME_WAIT state, 4505065Swnj * starting the time-wait timer, turning off the other 4515065Swnj * standard timers. 4525065Swnj */ 4535065Swnj case TCPS_FIN_WAIT_2: 4545065Swnj tp->t_state = TCPS_FIN_WAIT_2; 455*5074Swnj tcp_canceltimers(tp); 4565065Swnj tp->t_timer[TCPT_FINACK] = TCPSC_2MSL; 4575065Swnj break; 4585065Swnj 4594884Swnj /* 4605065Swnj * In TIME_WAIT state restart the 2 MSL time_wait timer. 4614884Swnj */ 4625065Swnj case TCPS_TIME_WAIT: 4635065Swnj tp->t_timer[TCPT_FINACK] = TCPSC_2MSL; 4645065Swnj break; 4654601Swnj } 4665065Swnj return; 4675065Swnj dropafterack: 4685065Swnj if ((tiflags & TH_RST) == 0) 4695065Swnj tcp_reflect(ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK); 4705065Swnj drop: 4715065Swnj m_freem(m); 4725065Swnj return; 4735065Swnj } 4745065Swnj 4755065Swnj /* 4765065Swnj * Insert segment ti into reassembly queue of tcp with 4775065Swnj * control block tp. Return TH_FIN if reassembly now includes 4785065Swnj * a segment with FIN. 4795065Swnj */ 4805065Swnj tcp_reass(tp, ti, endp) 4815065Swnj register struct tcpcb *tp; 4825065Swnj register struct tcpiphdr *ti; 4835065Swnj int *endp; 4845065Swnj { 4855065Swnj register struct tcpiphdr *q; 4865065Swnj int flags = 0; /* no FIN */ 4875065Swnj int overage; 4885065Swnj 4895065Swnj /* 4905065Swnj * If no data in this segment may want 4915065Swnj * to move data up to socket structure (if 4925065Swnj * connection is now established). 4935065Swnj */ 4945065Swnj if (ti->ti_len == 0) { 4955065Swnj m_freem(dtom(ti)); 4965065Swnj goto present; 4974601Swnj } 4984601Swnj 4995065Swnj /* 5005065Swnj * Find a segment which begins after this one does. 5015065Swnj */ 5025065Swnj for (q = tp->seg_next; q != (struct tcpiphdr *)tp; 5035065Swnj q = (struct tcpiphdr *)q->ti_next) 5045065Swnj if (SEQ_GT(q->ti_seq, ti->ti_seq)) 5055065Swnj break; 5064601Swnj 5075065Swnj /* 5085065Swnj * If there is a preceding segment, it may provide some of 5095065Swnj * our data already. If so, drop the data from the incoming 5105065Swnj * segment. If it provides all of our data, drop us. 5115065Swnj */ 5125065Swnj if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { 5135065Swnj register int i; 5145065Swnj q = (struct tcpiphdr *)(q->ti_prev); 5155065Swnj /* conversion to int (in i) handles seq wraparound */ 5165065Swnj i = q->ti_seq + q->ti_len - ti->ti_seq; 5175065Swnj if (i > 0) { 5184924Swnj if (i >= ti->ti_len) 5195065Swnj goto drop; 5205065Swnj m_adj(dtom(tp), i); 5215065Swnj ti->ti_len -= i; 5224924Swnj ti->ti_seq += i; 5234601Swnj } 5245065Swnj q = (struct tcpiphdr *)(q->ti_next); 5255065Swnj } 5264601Swnj 5275065Swnj /* 5285065Swnj * While we overlap succeeding segments trim them or, 5295065Swnj * if they are completely covered, dequeue them. 5305065Swnj */ 5315065Swnj while (q != (struct tcpiphdr *)tp && 5325065Swnj SEQ_GT(ti->ti_seq + ti->ti_len, q->ti_seq)) { 5335065Swnj register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; 5345065Swnj if (i < q->ti_len) { 5355065Swnj q->ti_len -= i; 5365065Swnj m_adj(dtom(q), i); 5375065Swnj break; 5384601Swnj } 5395065Swnj q = (struct tcpiphdr *)q->ti_next; 5405065Swnj m_freem(dtom(q->ti_prev)); 5415065Swnj remque(q->ti_prev); 5425065Swnj } 5434601Swnj 5445065Swnj /* 5455065Swnj * Stick new segment in its place. 5465065Swnj */ 5475065Swnj insque(ti, q->ti_prev); 5485065Swnj tp->seqcnt += ti->ti_len; 5494601Swnj 5505065Swnj /* 5515065Swnj * Calculate available space and discard segments for 5525065Swnj * which there is too much. 5535065Swnj */ 5545065Swnj overage = 5555065Swnj (so->so_rcv.sb_cc + tp->seqcnt) - so->so_rcv.sb_hiwat; 5565065Swnj if (overage > 0) { 5575065Swnj q = tp->seg_prev; 5585065Swnj for (;;) { 5595065Swnj register int i = MIN(q->ti_len, overage); 5605065Swnj overage -= i; 5615065Swnj tp->seqcnt -= i; 5625065Swnj q->ti_len -= i; 5635065Swnj m_adj(dtom(q), -i); 5645065Swnj if (q->ti_len) 5654645Swnj break; 5665065Swnj if (q == ti) 567*5074Swnj panic("tcp_reass dropall"); 5685065Swnj q = (struct tcpiphdr *)q->ti_prev; 5695065Swnj remque(q->ti_next); 5704645Swnj } 5714884Swnj } 5725065Swnj 5735065Swnj /* 5745065Swnj * Advance rcv_next through newly completed sequence space. 5755065Swnj */ 5765065Swnj while (ti->ti_seq == tp->rcv_nxt) { 5775065Swnj tp->rcv_nxt += ti->ti_len; 5785065Swnj flags = ti->ti_flags & TH_FIN; 5795065Swnj ti = (struct tcpiphdr *)ti->ti_next; 5805065Swnj if (ti == (struct tcpiphdr *)tp) 5815065Swnj break; 5824679Swnj } 5834679Swnj 5845065Swnj present: 5855065Swnj /* 5865065Swnj * Present data to user. 5875065Swnj */ 5885065Swnj if (tp->t_state < ESTAB) 5895065Swnj return (flags); 5904924Swnj ti = tp->seg_next; 5914924Swnj while (ti != (struct tcpiphdr *)tp && ti->ti_seq < tp->rcv_nxt) { 5924924Swnj remque(ti); 5934924Swnj sbappend(&so->so_rcv, dtom(ti)); 5944924Swnj tp->seqcnt -= ti->ti_len; 5954884Swnj if (tp->seqcnt < 0) 5965065Swnj panic("tcp_reass"); 5974924Swnj ti = (struct tcpiphdr *)ti->ti_next; 5984601Swnj } 599*5074Swnj if (so->so_state & SS_CANTRCVMORE) 600*5074Swnj sbflush(&so->so_rcv); 601*5074Swnj else 602*5074Swnj sorwakeup(so); 6035065Swnj return (flags); 6045065Swnj drop: 6055065Swnj m_freem(dtom(ti)); 6065065Swnj return (flags); 6074601Swnj } 608