1*8550Sroot /* tcp_input.c 1.77 82/10/16 */ 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" 98401Swnj #include "../netinet/in.h" 106351Ssam #include "../net/route.h" 118401Swnj #include "../netinet/in_pcb.h" 128401Swnj #include "../netinet/in_systm.h" 135085Swnj #include "../net/if.h" 148401Swnj #include "../netinet/ip.h" 158401Swnj #include "../netinet/ip_var.h" 168401Swnj #include "../netinet/tcp.h" 178401Swnj #include "../netinet/tcp_fsm.h" 188401Swnj #include "../netinet/tcp_seq.h" 198401Swnj #include "../netinet/tcp_timer.h" 208401Swnj #include "../netinet/tcp_var.h" 218401Swnj #include "../netinet/tcpip.h" 228401Swnj #include "../netinet/tcp_debug.h" 237300Ssam #include <errno.h> 244601Swnj 255300Sroot int tcpprintfs = 0; 264679Swnj int tcpcksum = 1; 278271Sroot struct mbuf tcp_mb; 285267Sroot struct tcpiphdr tcp_saveti; 295440Swnj extern tcpnodelack; 304601Swnj 315267Sroot struct tcpcb *tcp_newtcpcb(); 325065Swnj /* 335065Swnj * TCP input routine, follows pages 65-76 of the 345065Swnj * protocol specification dated September, 1981 very closely. 355065Swnj */ 364924Swnj tcp_input(m0) 374924Swnj struct mbuf *m0; 384601Swnj { 394924Swnj register struct tcpiphdr *ti; 404924Swnj struct inpcb *inp; 414924Swnj register struct mbuf *m; 425440Swnj struct mbuf *om = 0; 434924Swnj int len, tlen, off; 445391Swnj register struct tcpcb *tp = 0; 454924Swnj register int tiflags; 464803Swnj struct socket *so; 475109Swnj int todrop, acked; 485267Sroot short ostate; 496028Sroot struct in_addr laddr; 504924Swnj 514924Swnj /* 525244Sroot * Get IP and TCP header together in first mbuf. 535244Sroot * Note: IP leaves IP header in first mbuf. 544924Swnj */ 554924Swnj m = m0; 565020Sroot ti = mtod(m, struct tcpiphdr *); 575244Sroot if (((struct ip *)ti)->ip_hl > (sizeof (struct ip) >> 2)) 585208Swnj ip_stripoptions((struct ip *)ti, (struct mbuf *)0); 595307Sroot if (m->m_off > MMAXOFF || m->m_len < sizeof (struct tcpiphdr)) { 605307Sroot if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) { 615085Swnj tcpstat.tcps_hdrops++; 625307Sroot return; 635085Swnj } 645085Swnj ti = mtod(m, struct tcpiphdr *); 655085Swnj } 664601Swnj 674601Swnj /* 685244Sroot * Checksum extended TCP header and data. 694601Swnj */ 704924Swnj tlen = ((struct ip *)ti)->ip_len; 714924Swnj len = sizeof (struct ip) + tlen; 724679Swnj if (tcpcksum) { 734924Swnj ti->ti_next = ti->ti_prev = 0; 744924Swnj ti->ti_x1 = 0; 755223Swnj ti->ti_len = (u_short)tlen; 766320Swnj #if vax || pdp11 776161Ssam ti->ti_len = htons((u_short)ti->ti_len); 785223Swnj #endif 795231Swnj if (ti->ti_sum = in_cksum(m, len)) { 804924Swnj tcpstat.tcps_badsum++; 816211Swnj if (tcpprintfs) 826211Swnj printf("tcp cksum %x\n", ti->ti_sum); 835085Swnj goto drop; 844601Swnj } 854601Swnj } 864601Swnj 874601Swnj /* 885244Sroot * Check that TCP offset makes sense, 895440Swnj * pull out TCP options and adjust length. 904601Swnj */ 914924Swnj off = ti->ti_off << 2; 925231Swnj if (off < sizeof (struct tcphdr) || off > tlen) { 934924Swnj tcpstat.tcps_badoff++; 945085Swnj goto drop; 954924Swnj } 966211Swnj tlen -= off; 976211Swnj ti->ti_len = tlen; 985440Swnj if (off > sizeof (struct tcphdr)) { 995440Swnj if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { 1005440Swnj tcpstat.tcps_hdrops++; 1015440Swnj goto drop; 1025440Swnj } 1035440Swnj ti = mtod(m, struct tcpiphdr *); 1045440Swnj om = m_get(M_DONTWAIT); 1055440Swnj if (om == 0) 1065440Swnj goto drop; 1075440Swnj om->m_len = off - sizeof (struct tcphdr); 1085440Swnj { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr); 1096161Ssam bcopy(op, mtod(om, caddr_t), (unsigned)om->m_len); 1105440Swnj m->m_len -= om->m_len; 1116161Ssam bcopy(op+om->m_len, op, 1126161Ssam (unsigned)(m->m_len-sizeof (struct tcpiphdr))); 1135440Swnj } 1145440Swnj } 1155065Swnj tiflags = ti->ti_flags; 1164924Swnj 1176093Sroot /* 1186211Swnj * Drop TCP and IP headers. 1196093Sroot */ 1206093Sroot off += sizeof (struct ip); 1216093Sroot m->m_off += off; 1226093Sroot m->m_len -= off; 1236093Sroot 1246320Swnj #if vax || pdp11 1254924Swnj /* 1265244Sroot * Convert TCP protocol specific fields to host format. 1275085Swnj */ 1285085Swnj ti->ti_seq = ntohl(ti->ti_seq); 1295085Swnj ti->ti_ack = ntohl(ti->ti_ack); 1305085Swnj ti->ti_win = ntohs(ti->ti_win); 1315085Swnj ti->ti_urp = ntohs(ti->ti_urp); 1325231Swnj #endif 1335085Swnj 1345085Swnj /* 1358271Sroot * Locate pcb for segment. 1364924Swnj */ 1375065Swnj inp = in_pcblookup 1386028Sroot (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport, 1396028Sroot INPLOOKUP_WILDCARD); 1405065Swnj 1415065Swnj /* 1425065Swnj * If the state is CLOSED (i.e., TCB does not exist) then 1435244Sroot * all data in the incoming segment is discarded. 1445065Swnj */ 1455300Sroot if (inp == 0) 1465085Swnj goto dropwithreset; 1475065Swnj tp = intotcpcb(inp); 1485300Sroot if (tp == 0) 1495085Swnj goto dropwithreset; 1505109Swnj so = inp->inp_socket; 1515267Sroot if (so->so_options & SO_DEBUG) { 1525267Sroot ostate = tp->t_state; 1535267Sroot tcp_saveti = *ti; 1545267Sroot } 1557510Sroot if (so->so_options & SO_ACCEPTCONN) { 1567510Sroot so = sonewconn(so); 1577510Sroot if (so == 0) 1587510Sroot goto drop; 1597510Sroot inp = (struct inpcb *)so->so_pcb; 1607510Sroot inp->inp_laddr = ti->ti_dst; 1617510Sroot inp->inp_lport = ti->ti_dport; 1627510Sroot tp = intotcpcb(inp); 1637510Sroot tp->t_state = TCPS_LISTEN; 1647510Sroot } 1654601Swnj 1664601Swnj /* 1675162Swnj * Segment received on connection. 1685162Swnj * Reset idle time and keep-alive timer. 1695162Swnj */ 1705162Swnj tp->t_idle = 0; 1715162Swnj tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 1725162Swnj 1735162Swnj /* 1745440Swnj * Process options. 1755440Swnj */ 1765440Swnj if (om) { 1775440Swnj tcp_dooptions(tp, om); 1785440Swnj om = 0; 1795440Swnj } 1805440Swnj 1815440Swnj /* 1825085Swnj * Calculate amount of space in receive window, 1835085Swnj * and then do TCP input processing. 1844601Swnj */ 1855085Swnj tp->rcv_wnd = sbspace(&so->so_rcv); 1865231Swnj if (tp->rcv_wnd < 0) 1875231Swnj tp->rcv_wnd = 0; 1884601Swnj 1894601Swnj switch (tp->t_state) { 1904601Swnj 1915065Swnj /* 1925065Swnj * If the state is LISTEN then ignore segment if it contains an RST. 1935065Swnj * If the segment contains an ACK then it is bad and send a RST. 1945065Swnj * If it does not contain a SYN then it is not interesting; drop it. 1955085Swnj * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial 1965065Swnj * tp->iss, and send a segment: 1975085Swnj * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> 1985065Swnj * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. 1995065Swnj * Fill in remote peer address fields if not previously specified. 2005065Swnj * Enter SYN_RECEIVED state, and process any other fields of this 2015244Sroot * segment in this state. 2025065Swnj */ 2038271Sroot case TCPS_LISTEN: { 2048271Sroot struct mbuf *m = m_get(M_DONTWAIT); 2058271Sroot register struct sockaddr_in *sin; 2068271Sroot 2078271Sroot if (m == 0) 2088271Sroot goto drop; 2098271Sroot m->m_len = sizeof (struct sockaddr_in); 2105065Swnj if (tiflags & TH_RST) 2115065Swnj goto drop; 2125300Sroot if (tiflags & TH_ACK) 2135085Swnj goto dropwithreset; 2145300Sroot if ((tiflags & TH_SYN) == 0) 2155065Swnj goto drop; 2168271Sroot sin = mtod(m, struct sockaddr_in *); 2178271Sroot sin->sin_family = AF_INET; 2188271Sroot sin->sin_addr = ti->ti_src; 2198271Sroot sin->sin_port = ti->ti_sport; 2206028Sroot laddr = inp->inp_laddr; 2216028Sroot if (inp->inp_laddr.s_addr == 0) 2226028Sroot inp->inp_laddr = ti->ti_dst; 2238271Sroot if (in_pcbconnect(inp, m)) { 2246028Sroot inp->inp_laddr = laddr; 2258271Sroot m_free(m); 2265244Sroot goto drop; 2276028Sroot } 2288271Sroot m_free(m); 2295244Sroot tp->t_template = tcp_template(tp); 2305244Sroot if (tp->t_template == 0) { 2315244Sroot in_pcbdisconnect(inp); 2326028Sroot inp->inp_laddr = laddr; 2336320Swnj tp = 0; 2345244Sroot goto drop; 2355244Sroot } 2365085Swnj tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 2375065Swnj tp->irs = ti->ti_seq; 2385085Swnj tcp_sendseqinit(tp); 2395085Swnj tcp_rcvseqinit(tp); 2405065Swnj tp->t_state = TCPS_SYN_RECEIVED; 2415244Sroot tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 2425085Swnj goto trimthenstep6; 2438271Sroot } 2444601Swnj 2455065Swnj /* 2465065Swnj * If the state is SYN_SENT: 2475065Swnj * if seg contains an ACK, but not for our SYN, drop the input. 2485065Swnj * if seg contains a RST, then drop the connection. 2495065Swnj * if seg does not contain SYN, then drop it. 2505065Swnj * Otherwise this is an acceptable SYN segment 2515065Swnj * initialize tp->rcv_nxt and tp->irs 2525065Swnj * if seg contains ack then advance tp->snd_una 2535065Swnj * if SYN has been acked change to ESTABLISHED else SYN_RCVD state 2545065Swnj * arrange for segment to be acked (eventually) 2555065Swnj * continue processing rest of data/controls, beginning with URG 2565065Swnj */ 2575065Swnj case TCPS_SYN_SENT: 2585065Swnj if ((tiflags & TH_ACK) && 2595300Sroot /* this should be SEQ_LT; is SEQ_LEQ for BBN vax TCP only */ 2605300Sroot (SEQ_LT(ti->ti_ack, tp->iss) || 2615231Swnj SEQ_GT(ti->ti_ack, tp->snd_max))) 2625085Swnj goto dropwithreset; 2635065Swnj if (tiflags & TH_RST) { 2646320Swnj if (tiflags & TH_ACK) { 2655267Sroot tcp_drop(tp, ECONNREFUSED); 2666320Swnj tp = 0; 2676320Swnj } 2685065Swnj goto drop; 2694601Swnj } 2705065Swnj if ((tiflags & TH_SYN) == 0) 2715065Swnj goto drop; 2725231Swnj tp->snd_una = ti->ti_ack; 2735357Sroot if (SEQ_LT(tp->snd_nxt, tp->snd_una)) 2745357Sroot tp->snd_nxt = tp->snd_una; 2755244Sroot tp->t_timer[TCPT_REXMT] = 0; 2765065Swnj tp->irs = ti->ti_seq; 2775085Swnj tcp_rcvseqinit(tp); 2785085Swnj tp->t_flags |= TF_ACKNOW; 2795162Swnj if (SEQ_GT(tp->snd_una, tp->iss)) { 2805244Sroot soisconnected(so); 2815065Swnj tp->t_state = TCPS_ESTABLISHED; 2825162Swnj (void) tcp_reass(tp, (struct tcpiphdr *)0); 2835162Swnj } else 2845085Swnj tp->t_state = TCPS_SYN_RECEIVED; 2855085Swnj goto trimthenstep6; 2865085Swnj 2875085Swnj trimthenstep6: 2885085Swnj /* 2895231Swnj * Advance ti->ti_seq to correspond to first data byte. 2905085Swnj * If data, trim to stay within window, 2915085Swnj * dropping FIN if necessary. 2925085Swnj */ 2935231Swnj ti->ti_seq++; 2945085Swnj if (ti->ti_len > tp->rcv_wnd) { 2955085Swnj todrop = ti->ti_len - tp->rcv_wnd; 2965085Swnj m_adj(m, -todrop); 2975085Swnj ti->ti_len = tp->rcv_wnd; 2985085Swnj ti->ti_flags &= ~TH_FIN; 2995065Swnj } 3005263Swnj tp->snd_wl1 = ti->ti_seq - 1; 3015085Swnj goto step6; 3025065Swnj } 3034601Swnj 3045065Swnj /* 3055065Swnj * States other than LISTEN or SYN_SENT. 3065065Swnj * First check that at least some bytes of segment are within 3075065Swnj * receive window. 3085065Swnj */ 3095065Swnj if (tp->rcv_wnd == 0) { 3105065Swnj /* 3115065Swnj * If window is closed can only take segments at 3125231Swnj * window edge, and have to drop data and PUSH from 3135065Swnj * incoming segments. 3145065Swnj */ 3155300Sroot if (tp->rcv_nxt != ti->ti_seq) 3165065Swnj goto dropafterack; 3175085Swnj if (ti->ti_len > 0) { 3185690Swnj m_adj(m, ti->ti_len); 3195085Swnj ti->ti_len = 0; 3205085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 3215065Swnj } 3225065Swnj } else { 3235065Swnj /* 3245231Swnj * If segment begins before rcv_nxt, drop leading 3255065Swnj * data (and SYN); if nothing left, just ack. 3265065Swnj */ 3275690Swnj todrop = tp->rcv_nxt - ti->ti_seq; 3285690Swnj if (todrop > 0) { 3295085Swnj if (tiflags & TH_SYN) { 3305300Sroot tiflags &= ~TH_SYN; 3315690Swnj ti->ti_flags &= ~TH_SYN; 3325085Swnj ti->ti_seq++; 3335085Swnj if (ti->ti_urp > 1) 3345085Swnj ti->ti_urp--; 3355085Swnj else 3365085Swnj tiflags &= ~TH_URG; 3375085Swnj todrop--; 3385085Swnj } 3396211Swnj if (todrop > ti->ti_len || 3406211Swnj todrop == ti->ti_len && (tiflags&TH_FIN) == 0) 3415065Swnj goto dropafterack; 3425065Swnj m_adj(m, todrop); 3435065Swnj ti->ti_seq += todrop; 3445065Swnj ti->ti_len -= todrop; 3455085Swnj if (ti->ti_urp > todrop) 3465085Swnj ti->ti_urp -= todrop; 3475085Swnj else { 3485085Swnj tiflags &= ~TH_URG; 3495690Swnj ti->ti_flags &= ~TH_URG; 3505690Swnj ti->ti_urp = 0; 3515085Swnj } 3525065Swnj } 3535065Swnj /* 3545065Swnj * If segment ends after window, drop trailing data 3555085Swnj * (and PUSH and FIN); if nothing left, just ACK. 3565065Swnj */ 3575690Swnj todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); 3585690Swnj if (todrop > 0) { 3596211Swnj if (todrop >= ti->ti_len) 3605065Swnj goto dropafterack; 3615065Swnj m_adj(m, -todrop); 3625065Swnj ti->ti_len -= todrop; 3635085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 3645065Swnj } 3655065Swnj } 3664601Swnj 3675065Swnj /* 3685951Swnj * If a segment is received on a connection after the 3695951Swnj * user processes are gone, then RST the other end. 3705951Swnj */ 3717510Sroot if (so->so_state & SS_NOFDREF) { 3725951Swnj tcp_close(tp); 3736266Swnj tp = 0; 3745951Swnj goto dropwithreset; 3755951Swnj } 3765951Swnj 3775951Swnj /* 3785065Swnj * If the RST bit is set examine the state: 3795065Swnj * SYN_RECEIVED STATE: 3805065Swnj * If passive open, return to LISTEN state. 3815065Swnj * If active open, inform user that connection was refused. 3825065Swnj * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: 3835065Swnj * Inform user that connection was reset, and close tcb. 3845065Swnj * CLOSING, LAST_ACK, TIME_WAIT STATES 3855065Swnj * Close the tcb. 3865065Swnj */ 3875065Swnj if (tiflags&TH_RST) switch (tp->t_state) { 3885267Sroot 3895065Swnj case TCPS_SYN_RECEIVED: 3905085Swnj tcp_drop(tp, ECONNREFUSED); 3916320Swnj tp = 0; 3925065Swnj goto drop; 3934601Swnj 3945065Swnj case TCPS_ESTABLISHED: 3955065Swnj case TCPS_FIN_WAIT_1: 3965065Swnj case TCPS_FIN_WAIT_2: 3975065Swnj case TCPS_CLOSE_WAIT: 3985065Swnj tcp_drop(tp, ECONNRESET); 3996320Swnj tp = 0; 4005065Swnj goto drop; 4015065Swnj 4025065Swnj case TCPS_CLOSING: 4035065Swnj case TCPS_LAST_ACK: 4045065Swnj case TCPS_TIME_WAIT: 4055065Swnj tcp_close(tp); 4066320Swnj tp = 0; 4075065Swnj goto drop; 4084601Swnj } 4094601Swnj 4104601Swnj /* 4115065Swnj * If a SYN is in the window, then this is an 4125065Swnj * error and we send an RST and drop the connection. 4134601Swnj */ 4145065Swnj if (tiflags & TH_SYN) { 4155231Swnj tcp_drop(tp, ECONNRESET); 4166266Swnj tp = 0; 4175085Swnj goto dropwithreset; 4184601Swnj } 4194601Swnj 4204601Swnj /* 4215065Swnj * If the ACK bit is off we drop the segment and return. 4224601Swnj */ 4235085Swnj if ((tiflags & TH_ACK) == 0) 4245065Swnj goto drop; 4255065Swnj 4265065Swnj /* 4275065Swnj * Ack processing. 4285065Swnj */ 4294601Swnj switch (tp->t_state) { 4304601Swnj 4315065Swnj /* 4325065Swnj * In SYN_RECEIVED state if the ack ACKs our SYN then enter 4335065Swnj * ESTABLISHED state and continue processing, othewise 4345065Swnj * send an RST. 4355065Swnj */ 4365065Swnj case TCPS_SYN_RECEIVED: 4375085Swnj if (SEQ_GT(tp->snd_una, ti->ti_ack) || 4385231Swnj SEQ_GT(ti->ti_ack, tp->snd_max)) 4395085Swnj goto dropwithreset; 4405244Sroot tp->snd_una++; /* SYN acked */ 4415357Sroot if (SEQ_LT(tp->snd_nxt, tp->snd_una)) 4425357Sroot tp->snd_nxt = tp->snd_una; 4435244Sroot tp->t_timer[TCPT_REXMT] = 0; 4445085Swnj soisconnected(so); 4455085Swnj tp->t_state = TCPS_ESTABLISHED; 4465162Swnj (void) tcp_reass(tp, (struct tcpiphdr *)0); 4475244Sroot tp->snd_wl1 = ti->ti_seq - 1; 4485085Swnj /* fall into ... */ 4494601Swnj 4505065Swnj /* 4515065Swnj * In ESTABLISHED state: drop duplicate ACKs; ACK out of range 4525065Swnj * ACKs. If the ack is in the range 4535231Swnj * tp->snd_una < ti->ti_ack <= tp->snd_max 4545065Swnj * then advance tp->snd_una to ti->ti_ack and drop 4555065Swnj * data from the retransmission queue. If this ACK reflects 4565065Swnj * more up to date window information we update our window information. 4575065Swnj */ 4585065Swnj case TCPS_ESTABLISHED: 4595065Swnj case TCPS_FIN_WAIT_1: 4605065Swnj case TCPS_FIN_WAIT_2: 4615065Swnj case TCPS_CLOSE_WAIT: 4625065Swnj case TCPS_CLOSING: 4635244Sroot case TCPS_LAST_ACK: 4645244Sroot case TCPS_TIME_WAIT: 4655085Swnj #define ourfinisacked (acked > 0) 4665085Swnj 4675244Sroot if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) 4685065Swnj break; 4695300Sroot if (SEQ_GT(ti->ti_ack, tp->snd_max)) 4705065Swnj goto dropafterack; 4715085Swnj acked = ti->ti_ack - tp->snd_una; 4725951Swnj 4735951Swnj /* 4745951Swnj * If transmit timer is running and timed sequence 4755951Swnj * number was acked, update smoothed round trip time. 4765951Swnj */ 4775951Swnj if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) { 4785951Swnj if (tp->t_srtt == 0) 4795951Swnj tp->t_srtt = tp->t_rtt; 4805951Swnj else 4815951Swnj tp->t_srtt = 4825951Swnj tcp_alpha * tp->t_srtt + 4835951Swnj (1 - tcp_alpha) * tp->t_rtt; 4845951Swnj /* printf("rtt %d srtt*100 now %d\n", tp->t_rtt, (int)(tp->t_srtt*100)); */ 4855951Swnj tp->t_rtt = 0; 4865951Swnj } 4875951Swnj 4885307Sroot if (ti->ti_ack == tp->snd_max) 4895244Sroot tp->t_timer[TCPT_REXMT] = 0; 4905307Sroot else { 4915244Sroot TCPT_RANGESET(tp->t_timer[TCPT_REXMT], 4925244Sroot tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 4935951Swnj tp->t_rtt = 1; 4945300Sroot tp->t_rxtshift = 0; 4955085Swnj } 4965307Sroot if (acked > so->so_snd.sb_cc) { 4975307Sroot sbdrop(&so->so_snd, so->so_snd.sb_cc); 4985307Sroot tp->snd_wnd -= so->so_snd.sb_cc; 4995307Sroot } else { 5006161Ssam sbdrop(&so->so_snd, acked); 5015307Sroot tp->snd_wnd -= acked; 5025307Sroot acked = 0; 5035307Sroot } 5046434Swnj if ((so->so_snd.sb_flags & SB_WAIT) || so->so_snd.sb_sel) 5055300Sroot sowwakeup(so); 5065231Swnj tp->snd_una = ti->ti_ack; 5075357Sroot if (SEQ_LT(tp->snd_nxt, tp->snd_una)) 5085357Sroot tp->snd_nxt = tp->snd_una; 5095162Swnj 5104601Swnj switch (tp->t_state) { 5114601Swnj 5125065Swnj /* 5135065Swnj * In FIN_WAIT_1 STATE in addition to the processing 5145065Swnj * for the ESTABLISHED state if our FIN is now acknowledged 5155085Swnj * then enter FIN_WAIT_2. 5165065Swnj */ 5175065Swnj case TCPS_FIN_WAIT_1: 5185896Swnj if (ourfinisacked) { 5195896Swnj /* 5205896Swnj * If we can't receive any more 5215896Swnj * data, then closing user can proceed. 5225896Swnj */ 5235896Swnj if (so->so_state & SS_CANTRCVMORE) 5245896Swnj soisdisconnected(so); 5255085Swnj tp->t_state = TCPS_FIN_WAIT_2; 5265896Swnj } 5274601Swnj break; 5284601Swnj 5295065Swnj /* 5305065Swnj * In CLOSING STATE in addition to the processing for 5315065Swnj * the ESTABLISHED state if the ACK acknowledges our FIN 5325065Swnj * then enter the TIME-WAIT state, otherwise ignore 5335065Swnj * the segment. 5345065Swnj */ 5355065Swnj case TCPS_CLOSING: 5365244Sroot if (ourfinisacked) { 5375065Swnj tp->t_state = TCPS_TIME_WAIT; 5385244Sroot tcp_canceltimers(tp); 5395244Sroot tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 5405244Sroot soisdisconnected(so); 5415244Sroot } 5425244Sroot break; 5434601Swnj 5445065Swnj /* 5455085Swnj * The only thing that can arrive in LAST_ACK state 5465085Swnj * is an acknowledgment of our FIN. If our FIN is now 5475085Swnj * acknowledged, delete the TCB, enter the closed state 5485085Swnj * and return. 5495065Swnj */ 5505065Swnj case TCPS_LAST_ACK: 5516320Swnj if (ourfinisacked) { 5525065Swnj tcp_close(tp); 5536320Swnj tp = 0; 5546320Swnj } 5555065Swnj goto drop; 5564601Swnj 5575065Swnj /* 5585065Swnj * In TIME_WAIT state the only thing that should arrive 5595065Swnj * is a retransmission of the remote FIN. Acknowledge 5605065Swnj * it and restart the finack timer. 5615065Swnj */ 5625065Swnj case TCPS_TIME_WAIT: 5635162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 5645065Swnj goto dropafterack; 5654601Swnj } 5665085Swnj #undef ourfinisacked 5675085Swnj } 5684601Swnj 5695065Swnj step6: 5705065Swnj /* 5715244Sroot * Update window information. 5725244Sroot */ 5735300Sroot if (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq && 5745391Swnj (SEQ_LT(tp->snd_wl2, ti->ti_ack) || 5755300Sroot tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd)) { 5765244Sroot tp->snd_wnd = ti->ti_win; 5775244Sroot tp->snd_wl1 = ti->ti_seq; 5785244Sroot tp->snd_wl2 = ti->ti_ack; 5795244Sroot if (tp->snd_wnd > 0) 5805244Sroot tp->t_timer[TCPT_PERSIST] = 0; 5815244Sroot } 5825244Sroot 5835244Sroot /* 5845547Swnj * Process segments with URG. 5855065Swnj */ 5867267Swnj if ((tiflags & TH_URG) && ti->ti_urp && 5877267Swnj TCPS_HAVERCVDFIN(tp->t_state) == 0) { 5885547Swnj /* 5895547Swnj * If this segment advances the known urgent pointer, 5905547Swnj * then mark the data stream. This should not happen 5915547Swnj * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since 5925547Swnj * a FIN has been received from the remote side. 5935547Swnj * In these states we ignore the URG. 5945547Swnj */ 5955547Swnj if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { 5965547Swnj tp->rcv_up = ti->ti_seq + ti->ti_urp; 5975547Swnj so->so_oobmark = so->so_rcv.sb_cc + 5985547Swnj (tp->rcv_up - tp->rcv_nxt) - 1; 5995547Swnj if (so->so_oobmark == 0) 6005547Swnj so->so_state |= SS_RCVATMARK; 6018313Sroot sohasoutofband(so); 6025547Swnj tp->t_oobflags &= ~TCPOOB_HAVEDATA; 6035440Swnj } 6045547Swnj /* 6055547Swnj * Remove out of band data so doesn't get presented to user. 6065547Swnj * This can happen independent of advancing the URG pointer, 6075547Swnj * but if two URG's are pending at once, some out-of-band 6085547Swnj * data may creep in... ick. 6095547Swnj */ 6107510Sroot if (ti->ti_urp <= ti->ti_len) 6115547Swnj tcp_pulloutofband(so, ti); 6125419Swnj } 6134601Swnj 6144601Swnj /* 6155065Swnj * Process the segment text, merging it into the TCP sequencing queue, 6165065Swnj * and arranging for acknowledgment of receipt if necessary. 6175065Swnj * This process logically involves adjusting tp->rcv_wnd as data 6185065Swnj * is presented to the user (this happens in tcp_usrreq.c, 6195065Swnj * case PRU_RCVD). If a FIN has already been received on this 6205065Swnj * connection then we just ignore the text. 6214601Swnj */ 6225263Swnj if ((ti->ti_len || (tiflags&TH_FIN)) && 6235263Swnj TCPS_HAVERCVDFIN(tp->t_state) == 0) { 6245065Swnj tiflags = tcp_reass(tp, ti); 6255440Swnj if (tcpnodelack == 0) 6265440Swnj tp->t_flags |= TF_DELACK; 6275440Swnj else 6285440Swnj tp->t_flags |= TF_ACKNOW; 6295244Sroot } else { 6304924Swnj m_freem(m); 6315263Swnj tiflags &= ~TH_FIN; 6325244Sroot } 6334601Swnj 6344601Swnj /* 6355263Swnj * If FIN is received ACK the FIN and let the user know 6365263Swnj * that the connection is closing. 6374601Swnj */ 6385263Swnj if (tiflags & TH_FIN) { 6395244Sroot if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { 6405244Sroot socantrcvmore(so); 6415244Sroot tp->t_flags |= TF_ACKNOW; 6425244Sroot tp->rcv_nxt++; 6435244Sroot } 6445065Swnj switch (tp->t_state) { 6454601Swnj 6465065Swnj /* 6475065Swnj * In SYN_RECEIVED and ESTABLISHED STATES 6485065Swnj * enter the CLOSE_WAIT state. 6494884Swnj */ 6505065Swnj case TCPS_SYN_RECEIVED: 6515065Swnj case TCPS_ESTABLISHED: 6525065Swnj tp->t_state = TCPS_CLOSE_WAIT; 6535065Swnj break; 6544884Swnj 6555065Swnj /* 6565085Swnj * If still in FIN_WAIT_1 STATE FIN has not been acked so 6575085Swnj * enter the CLOSING state. 6584884Swnj */ 6595065Swnj case TCPS_FIN_WAIT_1: 6605085Swnj tp->t_state = TCPS_CLOSING; 6615065Swnj break; 6624601Swnj 6635065Swnj /* 6645065Swnj * In FIN_WAIT_2 state enter the TIME_WAIT state, 6655065Swnj * starting the time-wait timer, turning off the other 6665065Swnj * standard timers. 6675065Swnj */ 6685065Swnj case TCPS_FIN_WAIT_2: 6695244Sroot tp->t_state = TCPS_TIME_WAIT; 6705074Swnj tcp_canceltimers(tp); 6715162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 6725244Sroot soisdisconnected(so); 6735065Swnj break; 6745065Swnj 6754884Swnj /* 6765065Swnj * In TIME_WAIT state restart the 2 MSL time_wait timer. 6774884Swnj */ 6785065Swnj case TCPS_TIME_WAIT: 6795162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 6805065Swnj break; 6815085Swnj } 6824601Swnj } 6835267Sroot if (so->so_options & SO_DEBUG) 6845267Sroot tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0); 6855085Swnj 6865085Swnj /* 6875085Swnj * Return any desired output. 6885085Swnj */ 6896161Ssam (void) tcp_output(tp); 6905065Swnj return; 6915085Swnj 6925065Swnj dropafterack: 6935085Swnj /* 6946211Swnj * Generate an ACK dropping incoming segment if it occupies 6956211Swnj * sequence space, where the ACK reflects our state. 6965085Swnj */ 6976211Swnj if ((tiflags&TH_RST) || 6986211Swnj tlen == 0 && (tiflags&(TH_SYN|TH_FIN)) == 0) 6995085Swnj goto drop; 7006303Sroot if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 7016303Sroot tcp_trace(TA_RESPOND, ostate, tp, &tcp_saveti, 0); 7025391Swnj tcp_respond(tp, ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK); 7035231Swnj return; 7045085Swnj 7055085Swnj dropwithreset: 7065440Swnj if (om) 7076161Ssam (void) m_free(om); 7085085Swnj /* 7095244Sroot * Generate a RST, dropping incoming segment. 7105085Swnj * Make ACK acceptable to originator of segment. 7115085Swnj */ 7125085Swnj if (tiflags & TH_RST) 7135085Swnj goto drop; 7145085Swnj if (tiflags & TH_ACK) 7155391Swnj tcp_respond(tp, ti, (tcp_seq)0, ti->ti_ack, TH_RST); 7165085Swnj else { 7175085Swnj if (tiflags & TH_SYN) 7185085Swnj ti->ti_len++; 7196211Swnj tcp_respond(tp, ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, 7206211Swnj TH_RST|TH_ACK); 7215085Swnj } 7225231Swnj return; 7235085Swnj 7245065Swnj drop: 7255085Swnj /* 7265085Swnj * Drop space held by incoming segment and return. 7275085Swnj */ 7286303Sroot if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 7296303Sroot tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0); 7305065Swnj m_freem(m); 7315267Sroot return; 7325065Swnj } 7335065Swnj 7345440Swnj tcp_dooptions(tp, om) 7355440Swnj struct tcpcb *tp; 7365440Swnj struct mbuf *om; 7375419Swnj { 7385440Swnj register u_char *cp; 7395440Swnj int opt, optlen, cnt; 7405419Swnj 7415440Swnj cp = mtod(om, u_char *); 7425440Swnj cnt = om->m_len; 7435440Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 7445440Swnj opt = cp[0]; 7455440Swnj if (opt == TCPOPT_EOL) 7465440Swnj break; 7475440Swnj if (opt == TCPOPT_NOP) 7485440Swnj optlen = 1; 7495440Swnj else 7505440Swnj optlen = cp[1]; 7515440Swnj switch (opt) { 7525440Swnj 7535440Swnj default: 7545440Swnj break; 7555440Swnj 7565440Swnj case TCPOPT_MAXSEG: 7575440Swnj if (optlen != 4) 7585440Swnj continue; 7595440Swnj tp->t_maxseg = *(u_short *)(cp + 2); 7606320Swnj #if vax || pdp11 7616161Ssam tp->t_maxseg = ntohs((u_short)tp->t_maxseg); 7625440Swnj #endif 7635440Swnj break; 7645419Swnj } 7655419Swnj } 7666161Ssam (void) m_free(om); 7675419Swnj } 7685419Swnj 7695419Swnj /* 7705547Swnj * Pull out of band byte out of a segment so 7715547Swnj * it doesn't appear in the user's data queue. 7725547Swnj * It is still reflected in the segment length for 7735547Swnj * sequencing purposes. 7745547Swnj */ 7755547Swnj tcp_pulloutofband(so, ti) 7765547Swnj struct socket *so; 7775547Swnj struct tcpiphdr *ti; 7785547Swnj { 7795547Swnj register struct mbuf *m; 7806116Swnj int cnt = ti->ti_urp - 1; 7815547Swnj 7825547Swnj m = dtom(ti); 7835547Swnj while (cnt >= 0) { 7845547Swnj if (m->m_len > cnt) { 7855547Swnj char *cp = mtod(m, caddr_t) + cnt; 7865547Swnj struct tcpcb *tp = sototcpcb(so); 7875547Swnj 7885547Swnj tp->t_iobc = *cp; 7895547Swnj tp->t_oobflags |= TCPOOB_HAVEDATA; 7906161Ssam bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1)); 7915547Swnj m->m_len--; 7925547Swnj return; 7935547Swnj } 7945547Swnj cnt -= m->m_len; 7955547Swnj m = m->m_next; 7965547Swnj if (m == 0) 7975547Swnj break; 7985547Swnj } 7995547Swnj panic("tcp_pulloutofband"); 8005547Swnj } 8015547Swnj 8025547Swnj /* 8035065Swnj * Insert segment ti into reassembly queue of tcp with 8045065Swnj * control block tp. Return TH_FIN if reassembly now includes 8055065Swnj * a segment with FIN. 8065065Swnj */ 8075109Swnj tcp_reass(tp, ti) 8085065Swnj register struct tcpcb *tp; 8095065Swnj register struct tcpiphdr *ti; 8105065Swnj { 8115065Swnj register struct tcpiphdr *q; 8125085Swnj struct socket *so = tp->t_inpcb->inp_socket; 8135263Swnj struct mbuf *m; 8145263Swnj int flags; 8155065Swnj 8165065Swnj /* 8175162Swnj * Call with ti==0 after become established to 8185162Swnj * force pre-ESTABLISHED data up to user socket. 8195065Swnj */ 8205162Swnj if (ti == 0) 8215065Swnj goto present; 8224601Swnj 8235065Swnj /* 8245065Swnj * Find a segment which begins after this one does. 8255065Swnj */ 8265065Swnj for (q = tp->seg_next; q != (struct tcpiphdr *)tp; 8275065Swnj q = (struct tcpiphdr *)q->ti_next) 8285065Swnj if (SEQ_GT(q->ti_seq, ti->ti_seq)) 8295065Swnj break; 8304601Swnj 8315065Swnj /* 8325065Swnj * If there is a preceding segment, it may provide some of 8335065Swnj * our data already. If so, drop the data from the incoming 8345065Swnj * segment. If it provides all of our data, drop us. 8355065Swnj */ 8365065Swnj if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { 8375065Swnj register int i; 8385690Swnj q = (struct tcpiphdr *)q->ti_prev; 8395065Swnj /* conversion to int (in i) handles seq wraparound */ 8405065Swnj i = q->ti_seq + q->ti_len - ti->ti_seq; 8415065Swnj if (i > 0) { 8424924Swnj if (i >= ti->ti_len) 8435065Swnj goto drop; 8447338Swnj m_adj(dtom(ti), i); 8455065Swnj ti->ti_len -= i; 8464924Swnj ti->ti_seq += i; 8474601Swnj } 8485065Swnj q = (struct tcpiphdr *)(q->ti_next); 8495065Swnj } 8504601Swnj 8515065Swnj /* 8525065Swnj * While we overlap succeeding segments trim them or, 8535065Swnj * if they are completely covered, dequeue them. 8545065Swnj */ 8555690Swnj while (q != (struct tcpiphdr *)tp) { 8565065Swnj register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; 8575690Swnj if (i <= 0) 8585690Swnj break; 8595065Swnj if (i < q->ti_len) { 8605690Swnj q->ti_seq += i; 8615065Swnj q->ti_len -= i; 8625065Swnj m_adj(dtom(q), i); 8635065Swnj break; 8644601Swnj } 8655065Swnj q = (struct tcpiphdr *)q->ti_next; 8665623Swnj m = dtom(q->ti_prev); 8675065Swnj remque(q->ti_prev); 8685623Swnj m_freem(m); 8695065Swnj } 8704601Swnj 8715065Swnj /* 8725065Swnj * Stick new segment in its place. 8735065Swnj */ 8745065Swnj insque(ti, q->ti_prev); 8754601Swnj 8765065Swnj present: 8775065Swnj /* 8785244Sroot * Present data to user, advancing rcv_nxt through 8795244Sroot * completed sequence space. 8805065Swnj */ 8815263Swnj if (TCPS_HAVERCVDSYN(tp->t_state) == 0) 8825244Sroot return (0); 8834924Swnj ti = tp->seg_next; 8845263Swnj if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) 8855263Swnj return (0); 8865263Swnj if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) 8875263Swnj return (0); 8885263Swnj do { 8895244Sroot tp->rcv_nxt += ti->ti_len; 8905244Sroot flags = ti->ti_flags & TH_FIN; 8914924Swnj remque(ti); 8925263Swnj m = dtom(ti); 8934924Swnj ti = (struct tcpiphdr *)ti->ti_next; 8945263Swnj if (so->so_state & SS_CANTRCVMORE) 8956161Ssam m_freem(m); 896*8550Sroot else { 897*8550Sroot SBCHECK(&so->so_rcv, "tcp_input before"); 8985263Swnj sbappend(&so->so_rcv, m); 899*8550Sroot SBCHECK(&so->so_rcv, "tcp_input after"); 900*8550Sroot } 9015263Swnj } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); 9025263Swnj sorwakeup(so); 9035065Swnj return (flags); 9045065Swnj drop: 9055065Swnj m_freem(dtom(ti)); 9065263Swnj return (0); 9074601Swnj } 908