1*11730Ssam /* tcp_input.c 1.90 83/03/27 */ 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" 910894Ssam #include "../h/errno.h" 1010894Ssam 1110894Ssam #include "../net/if.h" 1210894Ssam #include "../net/route.h" 1310894Ssam 148401Swnj #include "../netinet/in.h" 158401Swnj #include "../netinet/in_pcb.h" 168401Swnj #include "../netinet/in_systm.h" 178401Swnj #include "../netinet/ip.h" 188401Swnj #include "../netinet/ip_var.h" 198401Swnj #include "../netinet/tcp.h" 208401Swnj #include "../netinet/tcp_fsm.h" 218401Swnj #include "../netinet/tcp_seq.h" 228401Swnj #include "../netinet/tcp_timer.h" 238401Swnj #include "../netinet/tcp_var.h" 248401Swnj #include "../netinet/tcpip.h" 258401Swnj #include "../netinet/tcp_debug.h" 264601Swnj 275300Sroot int tcpprintfs = 0; 284679Swnj int tcpcksum = 1; 295267Sroot struct tcpiphdr tcp_saveti; 305440Swnj extern tcpnodelack; 314601Swnj 325267Sroot struct tcpcb *tcp_newtcpcb(); 335065Swnj /* 345065Swnj * TCP input routine, follows pages 65-76 of the 355065Swnj * protocol specification dated September, 1981 very closely. 365065Swnj */ 374924Swnj tcp_input(m0) 384924Swnj struct mbuf *m0; 394601Swnj { 404924Swnj register struct tcpiphdr *ti; 414924Swnj struct inpcb *inp; 424924Swnj register struct mbuf *m; 435440Swnj struct mbuf *om = 0; 444924Swnj int len, tlen, off; 455391Swnj register struct tcpcb *tp = 0; 464924Swnj register int tiflags; 474803Swnj struct socket *so; 485109Swnj int todrop, acked; 495267Sroot short ostate; 506028Sroot struct in_addr laddr; 5110769Ssam int dropsocket = 0; 524924Swnj 534924Swnj /* 545244Sroot * Get IP and TCP header together in first mbuf. 555244Sroot * Note: IP leaves IP header in first mbuf. 564924Swnj */ 574924Swnj m = m0; 585020Sroot ti = mtod(m, struct tcpiphdr *); 595244Sroot if (((struct ip *)ti)->ip_hl > (sizeof (struct ip) >> 2)) 605208Swnj ip_stripoptions((struct ip *)ti, (struct mbuf *)0); 615307Sroot if (m->m_off > MMAXOFF || m->m_len < sizeof (struct tcpiphdr)) { 625307Sroot if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) { 635085Swnj tcpstat.tcps_hdrops++; 645307Sroot return; 655085Swnj } 665085Swnj ti = mtod(m, struct tcpiphdr *); 675085Swnj } 684601Swnj 694601Swnj /* 705244Sroot * Checksum extended TCP header and data. 714601Swnj */ 724924Swnj tlen = ((struct ip *)ti)->ip_len; 734924Swnj len = sizeof (struct ip) + tlen; 744679Swnj if (tcpcksum) { 754924Swnj ti->ti_next = ti->ti_prev = 0; 764924Swnj ti->ti_x1 = 0; 775223Swnj ti->ti_len = (u_short)tlen; 786161Ssam ti->ti_len = htons((u_short)ti->ti_len); 795231Swnj if (ti->ti_sum = in_cksum(m, len)) { 804924Swnj tcpstat.tcps_badsum++; 815085Swnj goto drop; 824601Swnj } 834601Swnj } 844601Swnj 854601Swnj /* 865244Sroot * Check that TCP offset makes sense, 875440Swnj * pull out TCP options and adjust length. 884601Swnj */ 894924Swnj off = ti->ti_off << 2; 905231Swnj if (off < sizeof (struct tcphdr) || off > tlen) { 914924Swnj tcpstat.tcps_badoff++; 925085Swnj goto drop; 934924Swnj } 946211Swnj tlen -= off; 956211Swnj ti->ti_len = tlen; 965440Swnj if (off > sizeof (struct tcphdr)) { 975440Swnj if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { 985440Swnj tcpstat.tcps_hdrops++; 99*11730Ssam return; 1005440Swnj } 1015440Swnj ti = mtod(m, struct tcpiphdr *); 1029642Ssam om = m_get(M_DONTWAIT, MT_DATA); 1035440Swnj if (om == 0) 1045440Swnj goto drop; 1055440Swnj om->m_len = off - sizeof (struct tcphdr); 1065440Swnj { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr); 1076161Ssam bcopy(op, mtod(om, caddr_t), (unsigned)om->m_len); 1085440Swnj m->m_len -= om->m_len; 1096161Ssam bcopy(op+om->m_len, op, 1106161Ssam (unsigned)(m->m_len-sizeof (struct tcpiphdr))); 1115440Swnj } 1125440Swnj } 1135065Swnj tiflags = ti->ti_flags; 1144924Swnj 1156093Sroot /* 1166211Swnj * Drop TCP and IP headers. 1176093Sroot */ 1186093Sroot off += sizeof (struct ip); 1196093Sroot m->m_off += off; 1206093Sroot m->m_len -= off; 1216093Sroot 1224924Swnj /* 1235244Sroot * Convert TCP protocol specific fields to host format. 1245085Swnj */ 1255085Swnj ti->ti_seq = ntohl(ti->ti_seq); 1265085Swnj ti->ti_ack = ntohl(ti->ti_ack); 1275085Swnj ti->ti_win = ntohs(ti->ti_win); 1285085Swnj ti->ti_urp = ntohs(ti->ti_urp); 1295085Swnj 1305085Swnj /* 1318271Sroot * Locate pcb for segment. 1324924Swnj */ 1335065Swnj inp = in_pcblookup 1346028Sroot (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport, 1356028Sroot INPLOOKUP_WILDCARD); 1365065Swnj 1375065Swnj /* 1385065Swnj * If the state is CLOSED (i.e., TCB does not exist) then 1395244Sroot * all data in the incoming segment is discarded. 1405065Swnj */ 1415300Sroot if (inp == 0) 1425085Swnj goto dropwithreset; 1435065Swnj tp = intotcpcb(inp); 1445300Sroot if (tp == 0) 1455085Swnj goto dropwithreset; 1465109Swnj so = inp->inp_socket; 1475267Sroot if (so->so_options & SO_DEBUG) { 1485267Sroot ostate = tp->t_state; 1495267Sroot tcp_saveti = *ti; 1505267Sroot } 1517510Sroot if (so->so_options & SO_ACCEPTCONN) { 1527510Sroot so = sonewconn(so); 1537510Sroot if (so == 0) 1547510Sroot goto drop; 15510769Ssam /* 15610769Ssam * This is ugly, but .... 15710769Ssam * 15810769Ssam * Mark socket as temporary until we're 15910769Ssam * committed to keeping it. The code at 16010769Ssam * ``drop'' and ``dropwithreset'' check the 16110769Ssam * flag dropsocket to see if the temporary 16210769Ssam * socket created here should be discarded. 16310769Ssam * We mark the socket as discardable until 16410769Ssam * we're committed to it below in TCPS_LISTEN. 16510769Ssam */ 16610769Ssam dropsocket++; 1677510Sroot inp = (struct inpcb *)so->so_pcb; 1687510Sroot inp->inp_laddr = ti->ti_dst; 1697510Sroot inp->inp_lport = ti->ti_dport; 1707510Sroot tp = intotcpcb(inp); 1717510Sroot tp->t_state = TCPS_LISTEN; 1727510Sroot } 1734601Swnj 1744601Swnj /* 1755162Swnj * Segment received on connection. 1765162Swnj * Reset idle time and keep-alive timer. 1775162Swnj */ 1785162Swnj tp->t_idle = 0; 1795162Swnj tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 1805162Swnj 1815162Swnj /* 1825440Swnj * Process options. 1835440Swnj */ 1845440Swnj if (om) { 1855440Swnj tcp_dooptions(tp, om); 1865440Swnj om = 0; 1875440Swnj } 1885440Swnj 1895440Swnj /* 1905085Swnj * Calculate amount of space in receive window, 1915085Swnj * and then do TCP input processing. 1924601Swnj */ 1935085Swnj tp->rcv_wnd = sbspace(&so->so_rcv); 1945231Swnj if (tp->rcv_wnd < 0) 1955231Swnj tp->rcv_wnd = 0; 1964601Swnj 1974601Swnj switch (tp->t_state) { 1984601Swnj 1995065Swnj /* 2005065Swnj * If the state is LISTEN then ignore segment if it contains an RST. 2015065Swnj * If the segment contains an ACK then it is bad and send a RST. 2025065Swnj * If it does not contain a SYN then it is not interesting; drop it. 2035085Swnj * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial 2045065Swnj * tp->iss, and send a segment: 2055085Swnj * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> 2065065Swnj * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. 2075065Swnj * Fill in remote peer address fields if not previously specified. 2085065Swnj * Enter SYN_RECEIVED state, and process any other fields of this 2095244Sroot * segment in this state. 2105065Swnj */ 2118271Sroot case TCPS_LISTEN: { 21210145Ssam struct mbuf *am; 2138271Sroot register struct sockaddr_in *sin; 2148271Sroot 2155065Swnj if (tiflags & TH_RST) 2165065Swnj goto drop; 2175300Sroot if (tiflags & TH_ACK) 2185085Swnj goto dropwithreset; 2195300Sroot if ((tiflags & TH_SYN) == 0) 2205065Swnj goto drop; 22110145Ssam am = m_get(M_DONTWAIT, MT_SONAME); 22210145Ssam if (am == NULL) 22310145Ssam goto drop; 22410145Ssam am->m_len = sizeof (struct sockaddr_in); 2258599Sroot sin = mtod(am, struct sockaddr_in *); 2268271Sroot sin->sin_family = AF_INET; 2278271Sroot sin->sin_addr = ti->ti_src; 2288271Sroot sin->sin_port = ti->ti_sport; 2296028Sroot laddr = inp->inp_laddr; 23010145Ssam if (inp->inp_laddr.s_addr == INADDR_ANY) 2316028Sroot inp->inp_laddr = ti->ti_dst; 2328599Sroot if (in_pcbconnect(inp, am)) { 2336028Sroot inp->inp_laddr = laddr; 2348716Sroot (void) m_free(am); 2355244Sroot goto drop; 2366028Sroot } 2378716Sroot (void) m_free(am); 2385244Sroot tp->t_template = tcp_template(tp); 2395244Sroot if (tp->t_template == 0) { 2405244Sroot in_pcbdisconnect(inp); 2416028Sroot inp->inp_laddr = laddr; 2426320Swnj tp = 0; 2435244Sroot goto drop; 2445244Sroot } 2455085Swnj tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 2465065Swnj tp->irs = ti->ti_seq; 2475085Swnj tcp_sendseqinit(tp); 2485085Swnj tcp_rcvseqinit(tp); 2495065Swnj tp->t_state = TCPS_SYN_RECEIVED; 2505244Sroot tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 25110769Ssam dropsocket = 0; /* committed to socket */ 2525085Swnj goto trimthenstep6; 2538271Sroot } 2544601Swnj 2555065Swnj /* 2565065Swnj * If the state is SYN_SENT: 2575065Swnj * if seg contains an ACK, but not for our SYN, drop the input. 2585065Swnj * if seg contains a RST, then drop the connection. 2595065Swnj * if seg does not contain SYN, then drop it. 2605065Swnj * Otherwise this is an acceptable SYN segment 2615065Swnj * initialize tp->rcv_nxt and tp->irs 2625065Swnj * if seg contains ack then advance tp->snd_una 2635065Swnj * if SYN has been acked change to ESTABLISHED else SYN_RCVD state 2645065Swnj * arrange for segment to be acked (eventually) 2655065Swnj * continue processing rest of data/controls, beginning with URG 2665065Swnj */ 2675065Swnj case TCPS_SYN_SENT: 2685065Swnj if ((tiflags & TH_ACK) && 2695300Sroot /* this should be SEQ_LT; is SEQ_LEQ for BBN vax TCP only */ 2705300Sroot (SEQ_LT(ti->ti_ack, tp->iss) || 2715231Swnj SEQ_GT(ti->ti_ack, tp->snd_max))) 2725085Swnj goto dropwithreset; 2735065Swnj if (tiflags & TH_RST) { 27410394Ssam if (tiflags & TH_ACK) 27510394Ssam tp = tcp_drop(tp, ECONNREFUSED); 2765065Swnj goto drop; 2774601Swnj } 2785065Swnj if ((tiflags & TH_SYN) == 0) 2795065Swnj goto drop; 2805231Swnj tp->snd_una = ti->ti_ack; 2815357Sroot if (SEQ_LT(tp->snd_nxt, tp->snd_una)) 2825357Sroot tp->snd_nxt = tp->snd_una; 2835244Sroot tp->t_timer[TCPT_REXMT] = 0; 2845065Swnj tp->irs = ti->ti_seq; 2855085Swnj tcp_rcvseqinit(tp); 2865085Swnj tp->t_flags |= TF_ACKNOW; 2875162Swnj if (SEQ_GT(tp->snd_una, tp->iss)) { 2885244Sroot soisconnected(so); 2895065Swnj tp->t_state = TCPS_ESTABLISHED; 2905162Swnj (void) tcp_reass(tp, (struct tcpiphdr *)0); 2915162Swnj } else 2925085Swnj tp->t_state = TCPS_SYN_RECEIVED; 2935085Swnj goto trimthenstep6; 2945085Swnj 2955085Swnj trimthenstep6: 2965085Swnj /* 2975231Swnj * Advance ti->ti_seq to correspond to first data byte. 2985085Swnj * If data, trim to stay within window, 2995085Swnj * dropping FIN if necessary. 3005085Swnj */ 3015231Swnj ti->ti_seq++; 3025085Swnj if (ti->ti_len > tp->rcv_wnd) { 3035085Swnj todrop = ti->ti_len - tp->rcv_wnd; 3045085Swnj m_adj(m, -todrop); 3055085Swnj ti->ti_len = tp->rcv_wnd; 3065085Swnj ti->ti_flags &= ~TH_FIN; 3075065Swnj } 3085263Swnj tp->snd_wl1 = ti->ti_seq - 1; 3095085Swnj goto step6; 3105065Swnj } 3114601Swnj 3125065Swnj /* 3135065Swnj * States other than LISTEN or SYN_SENT. 3145065Swnj * First check that at least some bytes of segment are within 3155065Swnj * receive window. 3165065Swnj */ 3175065Swnj if (tp->rcv_wnd == 0) { 3185065Swnj /* 3195065Swnj * If window is closed can only take segments at 3205231Swnj * window edge, and have to drop data and PUSH from 3215065Swnj * incoming segments. 3225065Swnj */ 3235300Sroot if (tp->rcv_nxt != ti->ti_seq) 3245065Swnj goto dropafterack; 3255085Swnj if (ti->ti_len > 0) { 3265690Swnj m_adj(m, ti->ti_len); 3275085Swnj ti->ti_len = 0; 3285085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 3295065Swnj } 3305065Swnj } else { 3315065Swnj /* 3325231Swnj * If segment begins before rcv_nxt, drop leading 3335065Swnj * data (and SYN); if nothing left, just ack. 3345065Swnj */ 3355690Swnj todrop = tp->rcv_nxt - ti->ti_seq; 3365690Swnj if (todrop > 0) { 3375085Swnj if (tiflags & TH_SYN) { 3385300Sroot tiflags &= ~TH_SYN; 3395690Swnj ti->ti_flags &= ~TH_SYN; 3405085Swnj ti->ti_seq++; 3415085Swnj if (ti->ti_urp > 1) 3425085Swnj ti->ti_urp--; 3435085Swnj else 3445085Swnj tiflags &= ~TH_URG; 3455085Swnj todrop--; 3465085Swnj } 3476211Swnj if (todrop > ti->ti_len || 3486211Swnj todrop == ti->ti_len && (tiflags&TH_FIN) == 0) 3495065Swnj goto dropafterack; 3505065Swnj m_adj(m, todrop); 3515065Swnj ti->ti_seq += todrop; 3525065Swnj ti->ti_len -= todrop; 3535085Swnj if (ti->ti_urp > todrop) 3545085Swnj ti->ti_urp -= todrop; 3555085Swnj else { 3565085Swnj tiflags &= ~TH_URG; 3575690Swnj ti->ti_flags &= ~TH_URG; 3585690Swnj ti->ti_urp = 0; 3595085Swnj } 3605065Swnj } 3615065Swnj /* 3625065Swnj * If segment ends after window, drop trailing data 3635085Swnj * (and PUSH and FIN); if nothing left, just ACK. 3645065Swnj */ 3655690Swnj todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); 3665690Swnj if (todrop > 0) { 3676211Swnj if (todrop >= ti->ti_len) 3685065Swnj goto dropafterack; 3695065Swnj m_adj(m, -todrop); 3705065Swnj ti->ti_len -= todrop; 3715085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 3725065Swnj } 3735065Swnj } 3744601Swnj 3755065Swnj /* 37610013Ssam * If data is received on a connection after the 3775951Swnj * user processes are gone, then RST the other end. 3785951Swnj */ 37910394Ssam if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && 38010203Ssam ti->ti_len) { 38110394Ssam tp = tcp_close(tp); 3825951Swnj goto dropwithreset; 3835951Swnj } 3845951Swnj 3855951Swnj /* 3865065Swnj * If the RST bit is set examine the state: 3875065Swnj * SYN_RECEIVED STATE: 3885065Swnj * If passive open, return to LISTEN state. 3895065Swnj * If active open, inform user that connection was refused. 3905065Swnj * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: 3915065Swnj * Inform user that connection was reset, and close tcb. 3925065Swnj * CLOSING, LAST_ACK, TIME_WAIT STATES 3935065Swnj * Close the tcb. 3945065Swnj */ 3955065Swnj if (tiflags&TH_RST) switch (tp->t_state) { 3965267Sroot 3975065Swnj case TCPS_SYN_RECEIVED: 39810394Ssam tp = tcp_drop(tp, ECONNREFUSED); 3995065Swnj goto drop; 4004601Swnj 4015065Swnj case TCPS_ESTABLISHED: 4025065Swnj case TCPS_FIN_WAIT_1: 4035065Swnj case TCPS_FIN_WAIT_2: 4045065Swnj case TCPS_CLOSE_WAIT: 40510394Ssam tp = tcp_drop(tp, ECONNRESET); 4065065Swnj goto drop; 4075065Swnj 4085065Swnj case TCPS_CLOSING: 4095065Swnj case TCPS_LAST_ACK: 4105065Swnj case TCPS_TIME_WAIT: 41110394Ssam tp = tcp_close(tp); 4125065Swnj goto drop; 4134601Swnj } 4144601Swnj 4154601Swnj /* 4165065Swnj * If a SYN is in the window, then this is an 4175065Swnj * error and we send an RST and drop the connection. 4184601Swnj */ 4195065Swnj if (tiflags & TH_SYN) { 42010394Ssam tp = tcp_drop(tp, ECONNRESET); 4215085Swnj goto dropwithreset; 4224601Swnj } 4234601Swnj 4244601Swnj /* 4255065Swnj * If the ACK bit is off we drop the segment and return. 4264601Swnj */ 4275085Swnj if ((tiflags & TH_ACK) == 0) 4285065Swnj goto drop; 4295065Swnj 4305065Swnj /* 4315065Swnj * Ack processing. 4325065Swnj */ 4334601Swnj switch (tp->t_state) { 4344601Swnj 4355065Swnj /* 4365065Swnj * In SYN_RECEIVED state if the ack ACKs our SYN then enter 4375065Swnj * ESTABLISHED state and continue processing, othewise 4385065Swnj * send an RST. 4395065Swnj */ 4405065Swnj case TCPS_SYN_RECEIVED: 4415085Swnj if (SEQ_GT(tp->snd_una, ti->ti_ack) || 4425231Swnj SEQ_GT(ti->ti_ack, tp->snd_max)) 4435085Swnj goto dropwithreset; 4445244Sroot tp->snd_una++; /* SYN acked */ 4455357Sroot if (SEQ_LT(tp->snd_nxt, tp->snd_una)) 4465357Sroot tp->snd_nxt = tp->snd_una; 4475244Sroot tp->t_timer[TCPT_REXMT] = 0; 4485085Swnj soisconnected(so); 4495085Swnj tp->t_state = TCPS_ESTABLISHED; 4505162Swnj (void) tcp_reass(tp, (struct tcpiphdr *)0); 4515244Sroot tp->snd_wl1 = ti->ti_seq - 1; 4525085Swnj /* fall into ... */ 4534601Swnj 4545065Swnj /* 4555065Swnj * In ESTABLISHED state: drop duplicate ACKs; ACK out of range 4565065Swnj * ACKs. If the ack is in the range 4575231Swnj * tp->snd_una < ti->ti_ack <= tp->snd_max 4585065Swnj * then advance tp->snd_una to ti->ti_ack and drop 4595065Swnj * data from the retransmission queue. If this ACK reflects 4605065Swnj * more up to date window information we update our window information. 4615065Swnj */ 4625065Swnj case TCPS_ESTABLISHED: 4635065Swnj case TCPS_FIN_WAIT_1: 4645065Swnj case TCPS_FIN_WAIT_2: 4655065Swnj case TCPS_CLOSE_WAIT: 4665065Swnj case TCPS_CLOSING: 4675244Sroot case TCPS_LAST_ACK: 4685244Sroot case TCPS_TIME_WAIT: 4695085Swnj #define ourfinisacked (acked > 0) 4705085Swnj 4715244Sroot if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) 4725065Swnj break; 4735300Sroot if (SEQ_GT(ti->ti_ack, tp->snd_max)) 4745065Swnj goto dropafterack; 4755085Swnj acked = ti->ti_ack - tp->snd_una; 4765951Swnj 4775951Swnj /* 4785951Swnj * If transmit timer is running and timed sequence 4795951Swnj * number was acked, update smoothed round trip time. 4805951Swnj */ 4815951Swnj if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) { 4825951Swnj if (tp->t_srtt == 0) 4835951Swnj tp->t_srtt = tp->t_rtt; 4845951Swnj else 4855951Swnj tp->t_srtt = 4865951Swnj tcp_alpha * tp->t_srtt + 4875951Swnj (1 - tcp_alpha) * tp->t_rtt; 4885951Swnj tp->t_rtt = 0; 4895951Swnj } 4905951Swnj 4915307Sroot if (ti->ti_ack == tp->snd_max) 4925244Sroot tp->t_timer[TCPT_REXMT] = 0; 4935307Sroot else { 4945244Sroot TCPT_RANGESET(tp->t_timer[TCPT_REXMT], 4955244Sroot tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 4965951Swnj tp->t_rtt = 1; 4975300Sroot tp->t_rxtshift = 0; 4985085Swnj } 4995307Sroot if (acked > so->so_snd.sb_cc) { 5005307Sroot sbdrop(&so->so_snd, so->so_snd.sb_cc); 5015307Sroot tp->snd_wnd -= so->so_snd.sb_cc; 5025307Sroot } else { 5036161Ssam sbdrop(&so->so_snd, acked); 5045307Sroot tp->snd_wnd -= acked; 5055307Sroot acked = 0; 5065307Sroot } 5076434Swnj if ((so->so_snd.sb_flags & SB_WAIT) || so->so_snd.sb_sel) 5085300Sroot sowwakeup(so); 5095231Swnj tp->snd_una = ti->ti_ack; 5105357Sroot if (SEQ_LT(tp->snd_nxt, tp->snd_una)) 5115357Sroot tp->snd_nxt = tp->snd_una; 5125162Swnj 5134601Swnj switch (tp->t_state) { 5144601Swnj 5155065Swnj /* 5165065Swnj * In FIN_WAIT_1 STATE in addition to the processing 5175065Swnj * for the ESTABLISHED state if our FIN is now acknowledged 5185085Swnj * then enter FIN_WAIT_2. 5195065Swnj */ 5205065Swnj case TCPS_FIN_WAIT_1: 5215896Swnj if (ourfinisacked) { 5225896Swnj /* 5235896Swnj * If we can't receive any more 5245896Swnj * data, then closing user can proceed. 5255896Swnj */ 5265896Swnj if (so->so_state & SS_CANTRCVMORE) 5275896Swnj soisdisconnected(so); 5285085Swnj tp->t_state = TCPS_FIN_WAIT_2; 5295896Swnj } 5304601Swnj break; 5314601Swnj 5325065Swnj /* 5335065Swnj * In CLOSING STATE in addition to the processing for 5345065Swnj * the ESTABLISHED state if the ACK acknowledges our FIN 5355065Swnj * then enter the TIME-WAIT state, otherwise ignore 5365065Swnj * the segment. 5375065Swnj */ 5385065Swnj case TCPS_CLOSING: 5395244Sroot if (ourfinisacked) { 5405065Swnj tp->t_state = TCPS_TIME_WAIT; 5415244Sroot tcp_canceltimers(tp); 5425244Sroot tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 5435244Sroot soisdisconnected(so); 5445244Sroot } 5455244Sroot break; 5464601Swnj 5475065Swnj /* 5485085Swnj * The only thing that can arrive in LAST_ACK state 5495085Swnj * is an acknowledgment of our FIN. If our FIN is now 5505085Swnj * acknowledged, delete the TCB, enter the closed state 5515085Swnj * and return. 5525065Swnj */ 5535065Swnj case TCPS_LAST_ACK: 55410394Ssam if (ourfinisacked) 55510394Ssam tp = tcp_close(tp); 5565065Swnj goto drop; 5574601Swnj 5585065Swnj /* 5595065Swnj * In TIME_WAIT state the only thing that should arrive 5605065Swnj * is a retransmission of the remote FIN. Acknowledge 5615065Swnj * it and restart the finack timer. 5625065Swnj */ 5635065Swnj case TCPS_TIME_WAIT: 5645162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 5655065Swnj goto dropafterack; 5664601Swnj } 5675085Swnj #undef ourfinisacked 5685085Swnj } 5694601Swnj 5705065Swnj step6: 5715065Swnj /* 5725244Sroot * Update window information. 5735244Sroot */ 5745300Sroot if (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq && 5755391Swnj (SEQ_LT(tp->snd_wl2, ti->ti_ack) || 5765300Sroot tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd)) { 5775244Sroot tp->snd_wnd = ti->ti_win; 5785244Sroot tp->snd_wl1 = ti->ti_seq; 5795244Sroot tp->snd_wl2 = ti->ti_ack; 5808599Sroot if (tp->snd_wnd != 0) 5815244Sroot tp->t_timer[TCPT_PERSIST] = 0; 5825244Sroot } 5835244Sroot 5845244Sroot /* 5855547Swnj * Process segments with URG. 5865065Swnj */ 5877267Swnj if ((tiflags & TH_URG) && ti->ti_urp && 5887267Swnj TCPS_HAVERCVDFIN(tp->t_state) == 0) { 5895547Swnj /* 5905547Swnj * If this segment advances the known urgent pointer, 5915547Swnj * then mark the data stream. This should not happen 5925547Swnj * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since 5935547Swnj * a FIN has been received from the remote side. 5945547Swnj * In these states we ignore the URG. 5955547Swnj */ 5965547Swnj if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { 5975547Swnj tp->rcv_up = ti->ti_seq + ti->ti_urp; 5985547Swnj so->so_oobmark = so->so_rcv.sb_cc + 5995547Swnj (tp->rcv_up - tp->rcv_nxt) - 1; 6005547Swnj if (so->so_oobmark == 0) 6015547Swnj so->so_state |= SS_RCVATMARK; 6028313Sroot sohasoutofband(so); 6035547Swnj tp->t_oobflags &= ~TCPOOB_HAVEDATA; 6045440Swnj } 6055547Swnj /* 6065547Swnj * Remove out of band data so doesn't get presented to user. 6075547Swnj * This can happen independent of advancing the URG pointer, 6085547Swnj * but if two URG's are pending at once, some out-of-band 6095547Swnj * data may creep in... ick. 6105547Swnj */ 6117510Sroot if (ti->ti_urp <= ti->ti_len) 6125547Swnj tcp_pulloutofband(so, ti); 6135419Swnj } 6144601Swnj 6154601Swnj /* 6165065Swnj * Process the segment text, merging it into the TCP sequencing queue, 6175065Swnj * and arranging for acknowledgment of receipt if necessary. 6185065Swnj * This process logically involves adjusting tp->rcv_wnd as data 6195065Swnj * is presented to the user (this happens in tcp_usrreq.c, 6205065Swnj * case PRU_RCVD). If a FIN has already been received on this 6215065Swnj * connection then we just ignore the text. 6224601Swnj */ 6235263Swnj if ((ti->ti_len || (tiflags&TH_FIN)) && 6245263Swnj TCPS_HAVERCVDFIN(tp->t_state) == 0) { 6255065Swnj tiflags = tcp_reass(tp, ti); 6265440Swnj if (tcpnodelack == 0) 6275440Swnj tp->t_flags |= TF_DELACK; 6285440Swnj else 6295440Swnj tp->t_flags |= TF_ACKNOW; 6305244Sroot } else { 6314924Swnj m_freem(m); 6325263Swnj tiflags &= ~TH_FIN; 6335244Sroot } 6344601Swnj 6354601Swnj /* 6365263Swnj * If FIN is received ACK the FIN and let the user know 6375263Swnj * that the connection is closing. 6384601Swnj */ 6395263Swnj if (tiflags & TH_FIN) { 6405244Sroot if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { 6415244Sroot socantrcvmore(so); 6425244Sroot tp->t_flags |= TF_ACKNOW; 6435244Sroot tp->rcv_nxt++; 6445244Sroot } 6455065Swnj switch (tp->t_state) { 6464601Swnj 6475065Swnj /* 6485065Swnj * In SYN_RECEIVED and ESTABLISHED STATES 6495065Swnj * enter the CLOSE_WAIT state. 6504884Swnj */ 6515065Swnj case TCPS_SYN_RECEIVED: 6525065Swnj case TCPS_ESTABLISHED: 6535065Swnj tp->t_state = TCPS_CLOSE_WAIT; 6545065Swnj break; 6554884Swnj 6565065Swnj /* 6575085Swnj * If still in FIN_WAIT_1 STATE FIN has not been acked so 6585085Swnj * enter the CLOSING state. 6594884Swnj */ 6605065Swnj case TCPS_FIN_WAIT_1: 6615085Swnj tp->t_state = TCPS_CLOSING; 6625065Swnj break; 6634601Swnj 6645065Swnj /* 6655065Swnj * In FIN_WAIT_2 state enter the TIME_WAIT state, 6665065Swnj * starting the time-wait timer, turning off the other 6675065Swnj * standard timers. 6685065Swnj */ 6695065Swnj case TCPS_FIN_WAIT_2: 6705244Sroot tp->t_state = TCPS_TIME_WAIT; 6715074Swnj tcp_canceltimers(tp); 6725162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 6735244Sroot soisdisconnected(so); 6745065Swnj break; 6755065Swnj 6764884Swnj /* 6775065Swnj * In TIME_WAIT state restart the 2 MSL time_wait timer. 6784884Swnj */ 6795065Swnj case TCPS_TIME_WAIT: 6805162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 6815065Swnj break; 6825085Swnj } 6834601Swnj } 6845267Sroot if (so->so_options & SO_DEBUG) 6855267Sroot tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0); 6865085Swnj 6875085Swnj /* 6885085Swnj * Return any desired output. 6895085Swnj */ 6906161Ssam (void) tcp_output(tp); 6915065Swnj return; 6925085Swnj 6935065Swnj dropafterack: 6945085Swnj /* 6956211Swnj * Generate an ACK dropping incoming segment if it occupies 6966211Swnj * sequence space, where the ACK reflects our state. 6975085Swnj */ 6986211Swnj if ((tiflags&TH_RST) || 6996211Swnj tlen == 0 && (tiflags&(TH_SYN|TH_FIN)) == 0) 7005085Swnj goto drop; 7016303Sroot if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 7026303Sroot tcp_trace(TA_RESPOND, ostate, tp, &tcp_saveti, 0); 7035391Swnj tcp_respond(tp, ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK); 7045231Swnj return; 7055085Swnj 7065085Swnj dropwithreset: 7075440Swnj if (om) 7086161Ssam (void) m_free(om); 7095085Swnj /* 7105244Sroot * Generate a RST, dropping incoming segment. 7115085Swnj * Make ACK acceptable to originator of segment. 7125085Swnj */ 7135085Swnj if (tiflags & TH_RST) 7145085Swnj goto drop; 7155085Swnj if (tiflags & TH_ACK) 7165391Swnj tcp_respond(tp, ti, (tcp_seq)0, ti->ti_ack, TH_RST); 7175085Swnj else { 7185085Swnj if (tiflags & TH_SYN) 7195085Swnj ti->ti_len++; 7206211Swnj tcp_respond(tp, ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, 7216211Swnj TH_RST|TH_ACK); 7225085Swnj } 72310769Ssam /* destroy temporarily created socket */ 72410769Ssam if (dropsocket) 72510769Ssam (void) soabort(so); 7265231Swnj return; 7275085Swnj 7285065Swnj drop: 729*11730Ssam if (om) 730*11730Ssam (void) m_free(om); 7315085Swnj /* 7325085Swnj * Drop space held by incoming segment and return. 7335085Swnj */ 7346303Sroot if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 7356303Sroot tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0); 7365065Swnj m_freem(m); 73710769Ssam /* destroy temporarily created socket */ 73810769Ssam if (dropsocket) 73910769Ssam (void) soabort(so); 7405267Sroot return; 7415065Swnj } 7425065Swnj 7435440Swnj tcp_dooptions(tp, om) 7445440Swnj struct tcpcb *tp; 7455440Swnj struct mbuf *om; 7465419Swnj { 7475440Swnj register u_char *cp; 7485440Swnj int opt, optlen, cnt; 7495419Swnj 7505440Swnj cp = mtod(om, u_char *); 7515440Swnj cnt = om->m_len; 7525440Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 7535440Swnj opt = cp[0]; 7545440Swnj if (opt == TCPOPT_EOL) 7555440Swnj break; 7565440Swnj if (opt == TCPOPT_NOP) 7575440Swnj optlen = 1; 7585440Swnj else 7595440Swnj optlen = cp[1]; 7605440Swnj switch (opt) { 7615440Swnj 7625440Swnj default: 7635440Swnj break; 7645440Swnj 7655440Swnj case TCPOPT_MAXSEG: 7665440Swnj if (optlen != 4) 7675440Swnj continue; 7685440Swnj tp->t_maxseg = *(u_short *)(cp + 2); 7696161Ssam tp->t_maxseg = ntohs((u_short)tp->t_maxseg); 7705440Swnj break; 7715419Swnj } 7725419Swnj } 7736161Ssam (void) m_free(om); 7745419Swnj } 7755419Swnj 7765419Swnj /* 7775547Swnj * Pull out of band byte out of a segment so 7785547Swnj * it doesn't appear in the user's data queue. 7795547Swnj * It is still reflected in the segment length for 7805547Swnj * sequencing purposes. 7815547Swnj */ 7825547Swnj tcp_pulloutofband(so, ti) 7835547Swnj struct socket *so; 7845547Swnj struct tcpiphdr *ti; 7855547Swnj { 7865547Swnj register struct mbuf *m; 7876116Swnj int cnt = ti->ti_urp - 1; 7885547Swnj 7895547Swnj m = dtom(ti); 7905547Swnj while (cnt >= 0) { 7915547Swnj if (m->m_len > cnt) { 7925547Swnj char *cp = mtod(m, caddr_t) + cnt; 7935547Swnj struct tcpcb *tp = sototcpcb(so); 7945547Swnj 7955547Swnj tp->t_iobc = *cp; 7965547Swnj tp->t_oobflags |= TCPOOB_HAVEDATA; 7976161Ssam bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1)); 7985547Swnj m->m_len--; 7995547Swnj return; 8005547Swnj } 8015547Swnj cnt -= m->m_len; 8025547Swnj m = m->m_next; 8035547Swnj if (m == 0) 8045547Swnj break; 8055547Swnj } 8065547Swnj panic("tcp_pulloutofband"); 8075547Swnj } 8085547Swnj 8095547Swnj /* 8105065Swnj * Insert segment ti into reassembly queue of tcp with 8115065Swnj * control block tp. Return TH_FIN if reassembly now includes 8125065Swnj * a segment with FIN. 8135065Swnj */ 8145109Swnj tcp_reass(tp, ti) 8155065Swnj register struct tcpcb *tp; 8165065Swnj register struct tcpiphdr *ti; 8175065Swnj { 8185065Swnj register struct tcpiphdr *q; 8195085Swnj struct socket *so = tp->t_inpcb->inp_socket; 8205263Swnj struct mbuf *m; 8215263Swnj int flags; 8225065Swnj 8235065Swnj /* 8245162Swnj * Call with ti==0 after become established to 8255162Swnj * force pre-ESTABLISHED data up to user socket. 8265065Swnj */ 8275162Swnj if (ti == 0) 8285065Swnj goto present; 8294601Swnj 8305065Swnj /* 8315065Swnj * Find a segment which begins after this one does. 8325065Swnj */ 8335065Swnj for (q = tp->seg_next; q != (struct tcpiphdr *)tp; 8345065Swnj q = (struct tcpiphdr *)q->ti_next) 8355065Swnj if (SEQ_GT(q->ti_seq, ti->ti_seq)) 8365065Swnj break; 8374601Swnj 8385065Swnj /* 8395065Swnj * If there is a preceding segment, it may provide some of 8405065Swnj * our data already. If so, drop the data from the incoming 8415065Swnj * segment. If it provides all of our data, drop us. 8425065Swnj */ 8435065Swnj if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { 8445065Swnj register int i; 8455690Swnj q = (struct tcpiphdr *)q->ti_prev; 8465065Swnj /* conversion to int (in i) handles seq wraparound */ 8475065Swnj i = q->ti_seq + q->ti_len - ti->ti_seq; 8485065Swnj if (i > 0) { 8494924Swnj if (i >= ti->ti_len) 8505065Swnj goto drop; 8517338Swnj m_adj(dtom(ti), i); 8525065Swnj ti->ti_len -= i; 8534924Swnj ti->ti_seq += i; 8544601Swnj } 8555065Swnj q = (struct tcpiphdr *)(q->ti_next); 8565065Swnj } 8574601Swnj 8585065Swnj /* 8595065Swnj * While we overlap succeeding segments trim them or, 8605065Swnj * if they are completely covered, dequeue them. 8615065Swnj */ 8625690Swnj while (q != (struct tcpiphdr *)tp) { 8635065Swnj register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; 8645690Swnj if (i <= 0) 8655690Swnj break; 8665065Swnj if (i < q->ti_len) { 8675690Swnj q->ti_seq += i; 8685065Swnj q->ti_len -= i; 8695065Swnj m_adj(dtom(q), i); 8705065Swnj break; 8714601Swnj } 8725065Swnj q = (struct tcpiphdr *)q->ti_next; 8735623Swnj m = dtom(q->ti_prev); 8745065Swnj remque(q->ti_prev); 8755623Swnj m_freem(m); 8765065Swnj } 8774601Swnj 8785065Swnj /* 8795065Swnj * Stick new segment in its place. 8805065Swnj */ 8815065Swnj insque(ti, q->ti_prev); 8824601Swnj 8835065Swnj present: 8845065Swnj /* 8855244Sroot * Present data to user, advancing rcv_nxt through 8865244Sroot * completed sequence space. 8875065Swnj */ 8885263Swnj if (TCPS_HAVERCVDSYN(tp->t_state) == 0) 8895244Sroot return (0); 8904924Swnj ti = tp->seg_next; 8915263Swnj if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) 8925263Swnj return (0); 8935263Swnj if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) 8945263Swnj return (0); 8955263Swnj do { 8965244Sroot tp->rcv_nxt += ti->ti_len; 8975244Sroot flags = ti->ti_flags & TH_FIN; 8984924Swnj remque(ti); 8995263Swnj m = dtom(ti); 9004924Swnj ti = (struct tcpiphdr *)ti->ti_next; 9015263Swnj if (so->so_state & SS_CANTRCVMORE) 9026161Ssam m_freem(m); 90310145Ssam else 9045263Swnj sbappend(&so->so_rcv, m); 9055263Swnj } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); 9065263Swnj sorwakeup(so); 9075065Swnj return (flags); 9085065Swnj drop: 9095065Swnj m_freem(dtom(ti)); 9105263Swnj return (0); 9114601Swnj } 912