1*6116Swnj /* tcp_input.c 1.59 82/03/11 */ 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" 215267Sroot #include "../net/tcp_debug.h" 225109Swnj #include "../errno.h" 234601Swnj 245300Sroot int tcpprintfs = 0; 254679Swnj int tcpcksum = 1; 265244Sroot struct sockaddr_in tcp_in = { AF_INET }; 275267Sroot struct tcpiphdr tcp_saveti; 285440Swnj extern tcpnodelack; 294601Swnj 305267Sroot struct tcpcb *tcp_newtcpcb(); 315065Swnj /* 325065Swnj * TCP input routine, follows pages 65-76 of the 335065Swnj * protocol specification dated September, 1981 very closely. 345065Swnj */ 354924Swnj tcp_input(m0) 364924Swnj struct mbuf *m0; 374601Swnj { 384924Swnj register struct tcpiphdr *ti; 394924Swnj struct inpcb *inp; 404924Swnj register struct mbuf *m; 415440Swnj struct mbuf *om = 0; 424924Swnj int len, tlen, off; 435391Swnj register struct tcpcb *tp = 0; 444924Swnj register int tiflags; 454803Swnj struct socket *so; 465109Swnj int todrop, acked; 475267Sroot short ostate; 486028Sroot struct in_addr laddr; 494924Swnj 504601Swnj COUNT(TCP_INPUT); 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; 765223Swnj #if vax 775223Swnj ti->ti_len = htons(ti->ti_len); 785223Swnj #endif 795231Swnj if (ti->ti_sum = in_cksum(m, len)) { 804924Swnj tcpstat.tcps_badsum++; 815065Swnj printf("tcp cksum %x\n", ti->ti_sum); 825085Swnj goto drop; 834601Swnj } 844601Swnj } 854601Swnj 864601Swnj /* 875244Sroot * Check that TCP offset makes sense, 885440Swnj * pull out TCP options and adjust length. 894601Swnj */ 904924Swnj off = ti->ti_off << 2; 915231Swnj if (off < sizeof (struct tcphdr) || off > tlen) { 924924Swnj tcpstat.tcps_badoff++; 935085Swnj goto drop; 944924Swnj } 954924Swnj ti->ti_len = tlen - off; 965440Swnj if (off > sizeof (struct tcphdr)) { 975440Swnj if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { 985440Swnj tcpstat.tcps_hdrops++; 995440Swnj goto drop; 1005440Swnj } 1015440Swnj ti = mtod(m, struct tcpiphdr *); 1025440Swnj om = m_get(M_DONTWAIT); 1035440Swnj if (om == 0) 1045440Swnj goto drop; 1055440Swnj om->m_off = MMINOFF; 1065440Swnj om->m_len = off - sizeof (struct tcphdr); 1075440Swnj { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr); 1085440Swnj bcopy(op, mtod(om, caddr_t), om->m_len); 1095440Swnj m->m_len -= om->m_len; 1105440Swnj bcopy(op+om->m_len, op, m->m_len-sizeof (struct tcpiphdr)); 1115440Swnj } 1125440Swnj } 1135065Swnj tiflags = ti->ti_flags; 1144924Swnj 1156093Sroot /* 1166093Sroot * drop IP header 1176093Sroot */ 1186093Sroot off += sizeof (struct ip); 1196093Sroot m->m_off += off; 1206093Sroot m->m_len -= off; 1216093Sroot 1225231Swnj #if vax 1234924Swnj /* 1245244Sroot * Convert TCP protocol specific fields to host format. 1255085Swnj */ 1265085Swnj ti->ti_seq = ntohl(ti->ti_seq); 1275085Swnj ti->ti_ack = ntohl(ti->ti_ack); 1285085Swnj ti->ti_win = ntohs(ti->ti_win); 1295085Swnj ti->ti_urp = ntohs(ti->ti_urp); 1305231Swnj #endif 1315085Swnj 1325085Swnj /* 1335994Swnj * Locate pcb for segment. On match, update the local 1345994Swnj * address stored in the block to reflect anchoring. 1354924Swnj */ 1365065Swnj inp = in_pcblookup 1376028Sroot (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport, 1386028Sroot INPLOOKUP_WILDCARD); 1395065Swnj 1405065Swnj /* 1415065Swnj * If the state is CLOSED (i.e., TCB does not exist) then 1425244Sroot * all data in the incoming segment is discarded. 1435065Swnj */ 1445300Sroot if (inp == 0) 1455085Swnj goto dropwithreset; 1465065Swnj tp = intotcpcb(inp); 1475300Sroot if (tp == 0) 1485085Swnj goto dropwithreset; 1495109Swnj so = inp->inp_socket; 1505267Sroot if (so->so_options & SO_DEBUG) { 1515267Sroot ostate = tp->t_state; 1525267Sroot tcp_saveti = *ti; 1535267Sroot } 1544601Swnj 1554601Swnj /* 1565162Swnj * Segment received on connection. 1575162Swnj * Reset idle time and keep-alive timer. 1585162Swnj */ 1595162Swnj tp->t_idle = 0; 1605162Swnj tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 1615162Swnj 1625162Swnj /* 1635440Swnj * Process options. 1645440Swnj */ 1655440Swnj if (om) { 1665440Swnj tcp_dooptions(tp, om); 1675440Swnj om = 0; 1685440Swnj } 1695440Swnj 1705440Swnj /* 1715085Swnj * Calculate amount of space in receive window, 1725085Swnj * and then do TCP input processing. 1734601Swnj */ 1745085Swnj tp->rcv_wnd = sbspace(&so->so_rcv); 1755231Swnj if (tp->rcv_wnd < 0) 1765231Swnj tp->rcv_wnd = 0; 1774601Swnj 1784601Swnj switch (tp->t_state) { 1794601Swnj 1805065Swnj /* 1815065Swnj * If the state is LISTEN then ignore segment if it contains an RST. 1825065Swnj * If the segment contains an ACK then it is bad and send a RST. 1835065Swnj * If it does not contain a SYN then it is not interesting; drop it. 1845085Swnj * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial 1855065Swnj * tp->iss, and send a segment: 1865085Swnj * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK> 1875065Swnj * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. 1885065Swnj * Fill in remote peer address fields if not previously specified. 1895065Swnj * Enter SYN_RECEIVED state, and process any other fields of this 1905244Sroot * segment in this state. 1915065Swnj */ 1925065Swnj case TCPS_LISTEN: 1935065Swnj if (tiflags & TH_RST) 1945065Swnj goto drop; 1955300Sroot if (tiflags & TH_ACK) 1965085Swnj goto dropwithreset; 1975300Sroot if ((tiflags & TH_SYN) == 0) 1985065Swnj goto drop; 1995244Sroot tcp_in.sin_addr = ti->ti_src; 2005244Sroot tcp_in.sin_port = ti->ti_sport; 2016028Sroot laddr = inp->inp_laddr; 2026028Sroot if (inp->inp_laddr.s_addr == 0) 2036028Sroot inp->inp_laddr = ti->ti_dst; 2046028Sroot if (in_pcbconnect(inp, (struct sockaddr *)&tcp_in)) { 2056028Sroot inp->inp_laddr = laddr; 2065244Sroot goto drop; 2076028Sroot } 2085244Sroot tp->t_template = tcp_template(tp); 2095244Sroot if (tp->t_template == 0) { 2105244Sroot in_pcbdisconnect(inp); 2116028Sroot inp->inp_laddr = laddr; 2125244Sroot goto drop; 2135244Sroot } 2146028Sroot in_setsockaddr(inp); 2155085Swnj tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; 2165065Swnj tp->irs = ti->ti_seq; 2175085Swnj tcp_sendseqinit(tp); 2185085Swnj tcp_rcvseqinit(tp); 2195065Swnj tp->t_state = TCPS_SYN_RECEIVED; 2205244Sroot tp->t_timer[TCPT_KEEP] = TCPTV_KEEP; 2215085Swnj goto trimthenstep6; 2224601Swnj 2235065Swnj /* 2245065Swnj * If the state is SYN_SENT: 2255065Swnj * if seg contains an ACK, but not for our SYN, drop the input. 2265065Swnj * if seg contains a RST, then drop the connection. 2275065Swnj * if seg does not contain SYN, then drop it. 2285065Swnj * Otherwise this is an acceptable SYN segment 2295065Swnj * initialize tp->rcv_nxt and tp->irs 2305065Swnj * if seg contains ack then advance tp->snd_una 2315065Swnj * if SYN has been acked change to ESTABLISHED else SYN_RCVD state 2325065Swnj * arrange for segment to be acked (eventually) 2335065Swnj * continue processing rest of data/controls, beginning with URG 2345065Swnj */ 2355065Swnj case TCPS_SYN_SENT: 2365065Swnj if ((tiflags & TH_ACK) && 2375300Sroot /* this should be SEQ_LT; is SEQ_LEQ for BBN vax TCP only */ 2385300Sroot (SEQ_LT(ti->ti_ack, tp->iss) || 2395231Swnj SEQ_GT(ti->ti_ack, tp->snd_max))) 2405085Swnj goto dropwithreset; 2415065Swnj if (tiflags & TH_RST) { 2425065Swnj if (tiflags & TH_ACK) 2435267Sroot tcp_drop(tp, ECONNREFUSED); 2445065Swnj goto drop; 2454601Swnj } 2465065Swnj if ((tiflags & TH_SYN) == 0) 2475065Swnj goto drop; 2485231Swnj tp->snd_una = ti->ti_ack; 2495357Sroot if (SEQ_LT(tp->snd_nxt, tp->snd_una)) 2505357Sroot tp->snd_nxt = tp->snd_una; 2515244Sroot tp->t_timer[TCPT_REXMT] = 0; 2525065Swnj tp->irs = ti->ti_seq; 2535085Swnj tcp_rcvseqinit(tp); 2545085Swnj tp->t_flags |= TF_ACKNOW; 2555162Swnj if (SEQ_GT(tp->snd_una, tp->iss)) { 2565391Swnj if (so->so_options & SO_ACCEPTCONN) 2575391Swnj so->so_state |= SS_CONNAWAITING; 2585244Sroot soisconnected(so); 2595065Swnj tp->t_state = TCPS_ESTABLISHED; 2605162Swnj (void) tcp_reass(tp, (struct tcpiphdr *)0); 2615162Swnj } else 2625085Swnj tp->t_state = TCPS_SYN_RECEIVED; 2635085Swnj goto trimthenstep6; 2645085Swnj 2655085Swnj trimthenstep6: 2665085Swnj /* 2675231Swnj * Advance ti->ti_seq to correspond to first data byte. 2685085Swnj * If data, trim to stay within window, 2695085Swnj * dropping FIN if necessary. 2705085Swnj */ 2715231Swnj ti->ti_seq++; 2725085Swnj if (ti->ti_len > tp->rcv_wnd) { 2735085Swnj todrop = ti->ti_len - tp->rcv_wnd; 2745085Swnj m_adj(m, -todrop); 2755085Swnj ti->ti_len = tp->rcv_wnd; 2765085Swnj ti->ti_flags &= ~TH_FIN; 2775065Swnj } 2785263Swnj tp->snd_wl1 = ti->ti_seq - 1; 2795085Swnj goto step6; 2805065Swnj } 2814601Swnj 2825065Swnj /* 2835065Swnj * States other than LISTEN or SYN_SENT. 2845065Swnj * First check that at least some bytes of segment are within 2855065Swnj * receive window. 2865065Swnj */ 2875065Swnj if (tp->rcv_wnd == 0) { 2885065Swnj /* 2895065Swnj * If window is closed can only take segments at 2905231Swnj * window edge, and have to drop data and PUSH from 2915065Swnj * incoming segments. 2925065Swnj */ 2935300Sroot if (tp->rcv_nxt != ti->ti_seq) 2945065Swnj goto dropafterack; 2955085Swnj if (ti->ti_len > 0) { 2965690Swnj m_adj(m, ti->ti_len); 2975085Swnj ti->ti_len = 0; 2985085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 2995065Swnj } 3005065Swnj } else { 3015065Swnj /* 3025231Swnj * If segment begins before rcv_nxt, drop leading 3035065Swnj * data (and SYN); if nothing left, just ack. 3045065Swnj */ 3055690Swnj todrop = tp->rcv_nxt - ti->ti_seq; 3065690Swnj if (todrop > 0) { 3075085Swnj if (tiflags & TH_SYN) { 3085300Sroot tiflags &= ~TH_SYN; 3095690Swnj ti->ti_flags &= ~TH_SYN; 3105085Swnj ti->ti_seq++; 3115085Swnj if (ti->ti_urp > 1) 3125085Swnj ti->ti_urp--; 3135085Swnj else 3145085Swnj tiflags &= ~TH_URG; 3155085Swnj todrop--; 3165085Swnj } 3175300Sroot if (todrop > ti->ti_len) 3185065Swnj goto dropafterack; 3195065Swnj m_adj(m, todrop); 3205065Swnj ti->ti_seq += todrop; 3215065Swnj ti->ti_len -= todrop; 3225085Swnj if (ti->ti_urp > todrop) 3235085Swnj ti->ti_urp -= todrop; 3245085Swnj else { 3255085Swnj tiflags &= ~TH_URG; 3265690Swnj ti->ti_flags &= ~TH_URG; 3275690Swnj ti->ti_urp = 0; 3285085Swnj } 3295065Swnj } 3305065Swnj /* 3315065Swnj * If segment ends after window, drop trailing data 3325085Swnj * (and PUSH and FIN); if nothing left, just ACK. 3335065Swnj */ 3345690Swnj todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); 3355690Swnj if (todrop > 0) { 3365300Sroot if (todrop > ti->ti_len) 3375065Swnj goto dropafterack; 3385065Swnj m_adj(m, -todrop); 3395065Swnj ti->ti_len -= todrop; 3405085Swnj ti->ti_flags &= ~(TH_PUSH|TH_FIN); 3415065Swnj } 3425065Swnj } 3434601Swnj 3445065Swnj /* 3455951Swnj * If a segment is received on a connection after the 3465951Swnj * user processes are gone, then RST the other end. 3475951Swnj */ 3485951Swnj if (so->so_state & SS_USERGONE) { 3495951Swnj tcp_close(tp); 3505951Swnj goto dropwithreset; 3515951Swnj } 3525951Swnj 3535951Swnj /* 3545065Swnj * If the RST bit is set examine the state: 3555065Swnj * SYN_RECEIVED STATE: 3565065Swnj * If passive open, return to LISTEN state. 3575065Swnj * If active open, inform user that connection was refused. 3585065Swnj * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: 3595065Swnj * Inform user that connection was reset, and close tcb. 3605065Swnj * CLOSING, LAST_ACK, TIME_WAIT STATES 3615065Swnj * Close the tcb. 3625065Swnj */ 3635065Swnj if (tiflags&TH_RST) switch (tp->t_state) { 3645267Sroot 3655065Swnj case TCPS_SYN_RECEIVED: 3665065Swnj if (inp->inp_socket->so_options & SO_ACCEPTCONN) { 3675267Sroot /* a miniature tcp_close, but invisible to user */ 3685267Sroot (void) m_free(dtom(tp->t_template)); 3695267Sroot (void) m_free(dtom(tp)); 3705267Sroot inp->inp_ppcb = 0; 3715267Sroot tp = tcp_newtcpcb(inp); 3725085Swnj tp->t_state = TCPS_LISTEN; 3736028Sroot inp->inp_faddr.s_addr = 0; 3746028Sroot inp->inp_fport = 0; 3756028Sroot inp->inp_laddr.s_addr = 0; /* not quite right */ 3765065Swnj goto drop; 3774601Swnj } 3785085Swnj tcp_drop(tp, ECONNREFUSED); 3795065Swnj goto drop; 3804601Swnj 3815065Swnj case TCPS_ESTABLISHED: 3825065Swnj case TCPS_FIN_WAIT_1: 3835065Swnj case TCPS_FIN_WAIT_2: 3845065Swnj case TCPS_CLOSE_WAIT: 3855065Swnj tcp_drop(tp, ECONNRESET); 3865065Swnj goto drop; 3875065Swnj 3885065Swnj case TCPS_CLOSING: 3895065Swnj case TCPS_LAST_ACK: 3905065Swnj case TCPS_TIME_WAIT: 3915065Swnj tcp_close(tp); 3925065Swnj goto drop; 3934601Swnj } 3944601Swnj 3954601Swnj /* 3965065Swnj * If a SYN is in the window, then this is an 3975065Swnj * error and we send an RST and drop the connection. 3984601Swnj */ 3995065Swnj if (tiflags & TH_SYN) { 4005231Swnj tcp_drop(tp, ECONNRESET); 4015085Swnj goto dropwithreset; 4024601Swnj } 4034601Swnj 4044601Swnj /* 4055065Swnj * If the ACK bit is off we drop the segment and return. 4064601Swnj */ 4075085Swnj if ((tiflags & TH_ACK) == 0) 4085065Swnj goto drop; 4095065Swnj 4105065Swnj /* 4115065Swnj * Ack processing. 4125065Swnj */ 4134601Swnj switch (tp->t_state) { 4144601Swnj 4155065Swnj /* 4165065Swnj * In SYN_RECEIVED state if the ack ACKs our SYN then enter 4175065Swnj * ESTABLISHED state and continue processing, othewise 4185065Swnj * send an RST. 4195065Swnj */ 4205065Swnj case TCPS_SYN_RECEIVED: 4215085Swnj if (SEQ_GT(tp->snd_una, ti->ti_ack) || 4225231Swnj SEQ_GT(ti->ti_ack, tp->snd_max)) 4235085Swnj goto dropwithreset; 4245244Sroot tp->snd_una++; /* SYN acked */ 4255357Sroot if (SEQ_LT(tp->snd_nxt, tp->snd_una)) 4265357Sroot tp->snd_nxt = tp->snd_una; 4275244Sroot tp->t_timer[TCPT_REXMT] = 0; 4285391Swnj if (so->so_options & SO_ACCEPTCONN) 4295391Swnj so->so_state |= SS_CONNAWAITING; 4305085Swnj soisconnected(so); 4315085Swnj tp->t_state = TCPS_ESTABLISHED; 4325162Swnj (void) tcp_reass(tp, (struct tcpiphdr *)0); 4335244Sroot tp->snd_wl1 = ti->ti_seq - 1; 4345085Swnj /* fall into ... */ 4354601Swnj 4365065Swnj /* 4375065Swnj * In ESTABLISHED state: drop duplicate ACKs; ACK out of range 4385065Swnj * ACKs. If the ack is in the range 4395231Swnj * tp->snd_una < ti->ti_ack <= tp->snd_max 4405065Swnj * then advance tp->snd_una to ti->ti_ack and drop 4415065Swnj * data from the retransmission queue. If this ACK reflects 4425065Swnj * more up to date window information we update our window information. 4435065Swnj */ 4445065Swnj case TCPS_ESTABLISHED: 4455065Swnj case TCPS_FIN_WAIT_1: 4465065Swnj case TCPS_FIN_WAIT_2: 4475065Swnj case TCPS_CLOSE_WAIT: 4485065Swnj case TCPS_CLOSING: 4495244Sroot case TCPS_LAST_ACK: 4505244Sroot case TCPS_TIME_WAIT: 4515085Swnj #define ourfinisacked (acked > 0) 4525085Swnj 4535244Sroot if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) 4545065Swnj break; 4555300Sroot if (SEQ_GT(ti->ti_ack, tp->snd_max)) 4565065Swnj goto dropafterack; 4575085Swnj acked = ti->ti_ack - tp->snd_una; 4585951Swnj 4595951Swnj /* 4605951Swnj * If transmit timer is running and timed sequence 4615951Swnj * number was acked, update smoothed round trip time. 4625951Swnj */ 4635951Swnj if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) { 4645951Swnj if (tp->t_srtt == 0) 4655951Swnj tp->t_srtt = tp->t_rtt; 4665951Swnj else 4675951Swnj tp->t_srtt = 4685951Swnj tcp_alpha * tp->t_srtt + 4695951Swnj (1 - tcp_alpha) * tp->t_rtt; 4705951Swnj /* printf("rtt %d srtt*100 now %d\n", tp->t_rtt, (int)(tp->t_srtt*100)); */ 4715951Swnj tp->t_rtt = 0; 4725951Swnj } 4735951Swnj 4745307Sroot if (ti->ti_ack == tp->snd_max) 4755244Sroot tp->t_timer[TCPT_REXMT] = 0; 4765307Sroot else { 4775244Sroot TCPT_RANGESET(tp->t_timer[TCPT_REXMT], 4785244Sroot tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); 4795951Swnj tp->t_rtt = 1; 4805300Sroot tp->t_rxtshift = 0; 4815085Swnj } 4825307Sroot if (acked > so->so_snd.sb_cc) { 4835307Sroot sbdrop(&so->so_snd, so->so_snd.sb_cc); 4845307Sroot tp->snd_wnd -= so->so_snd.sb_cc; 4855307Sroot } else { 4865307Sroot sbdrop(&so->so_snd.sb_cc, acked); 4875307Sroot tp->snd_wnd -= acked; 4885307Sroot acked = 0; 4895307Sroot } 4905300Sroot if (so->so_snd.sb_flags & SB_WAIT) 4915300Sroot sowwakeup(so); 4925231Swnj tp->snd_una = ti->ti_ack; 4935357Sroot if (SEQ_LT(tp->snd_nxt, tp->snd_una)) 4945357Sroot tp->snd_nxt = tp->snd_una; 4955162Swnj 4964601Swnj switch (tp->t_state) { 4974601Swnj 4985065Swnj /* 4995065Swnj * In FIN_WAIT_1 STATE in addition to the processing 5005065Swnj * for the ESTABLISHED state if our FIN is now acknowledged 5015085Swnj * then enter FIN_WAIT_2. 5025065Swnj */ 5035065Swnj case TCPS_FIN_WAIT_1: 5045896Swnj if (ourfinisacked) { 5055896Swnj /* 5065896Swnj * If we can't receive any more 5075896Swnj * data, then closing user can proceed. 5085896Swnj */ 5095896Swnj if (so->so_state & SS_CANTRCVMORE) 5105896Swnj soisdisconnected(so); 5115085Swnj tp->t_state = TCPS_FIN_WAIT_2; 5125896Swnj } 5134601Swnj break; 5144601Swnj 5155065Swnj /* 5165065Swnj * In CLOSING STATE in addition to the processing for 5175065Swnj * the ESTABLISHED state if the ACK acknowledges our FIN 5185065Swnj * then enter the TIME-WAIT state, otherwise ignore 5195065Swnj * the segment. 5205065Swnj */ 5215065Swnj case TCPS_CLOSING: 5225244Sroot if (ourfinisacked) { 5235065Swnj tp->t_state = TCPS_TIME_WAIT; 5245244Sroot tcp_canceltimers(tp); 5255244Sroot tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 5265244Sroot soisdisconnected(so); 5275244Sroot } 5285244Sroot break; 5294601Swnj 5305065Swnj /* 5315085Swnj * The only thing that can arrive in LAST_ACK state 5325085Swnj * is an acknowledgment of our FIN. If our FIN is now 5335085Swnj * acknowledged, delete the TCB, enter the closed state 5345085Swnj * and return. 5355065Swnj */ 5365065Swnj case TCPS_LAST_ACK: 5375251Sroot if (ourfinisacked) 5385065Swnj tcp_close(tp); 5395065Swnj goto drop; 5404601Swnj 5415065Swnj /* 5425065Swnj * In TIME_WAIT state the only thing that should arrive 5435065Swnj * is a retransmission of the remote FIN. Acknowledge 5445065Swnj * it and restart the finack timer. 5455065Swnj */ 5465065Swnj case TCPS_TIME_WAIT: 5475162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 5485065Swnj goto dropafterack; 5494601Swnj } 5505085Swnj #undef ourfinisacked 5515085Swnj } 5524601Swnj 5535065Swnj step6: 5545065Swnj /* 5555244Sroot * Update window information. 5565244Sroot */ 5575300Sroot if (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq && 5585391Swnj (SEQ_LT(tp->snd_wl2, ti->ti_ack) || 5595300Sroot tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd)) { 5605244Sroot tp->snd_wnd = ti->ti_win; 5615244Sroot tp->snd_wl1 = ti->ti_seq; 5625244Sroot tp->snd_wl2 = ti->ti_ack; 5635244Sroot if (tp->snd_wnd > 0) 5645244Sroot tp->t_timer[TCPT_PERSIST] = 0; 5655244Sroot } 5665244Sroot 5675244Sroot /* 5685547Swnj * Process segments with URG. 5695065Swnj */ 5705547Swnj if ((tiflags & TH_URG) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { 5715547Swnj /* 5725547Swnj * If this segment advances the known urgent pointer, 5735547Swnj * then mark the data stream. This should not happen 5745547Swnj * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since 5755547Swnj * a FIN has been received from the remote side. 5765547Swnj * In these states we ignore the URG. 5775547Swnj */ 5785547Swnj if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { 5795547Swnj tp->rcv_up = ti->ti_seq + ti->ti_urp; 5805547Swnj so->so_oobmark = so->so_rcv.sb_cc + 5815547Swnj (tp->rcv_up - tp->rcv_nxt) - 1; 5825547Swnj if (so->so_oobmark == 0) 5835547Swnj so->so_state |= SS_RCVATMARK; 5845440Swnj #ifdef TCPTRUEOOB 5855547Swnj if ((tp->t_flags & TF_DOOOB) == 0) 5865440Swnj #endif 5875547Swnj sohasoutofband(so); 5885547Swnj tp->t_oobflags &= ~TCPOOB_HAVEDATA; 5895440Swnj } 5905547Swnj /* 5915547Swnj * Remove out of band data so doesn't get presented to user. 5925547Swnj * This can happen independent of advancing the URG pointer, 5935547Swnj * but if two URG's are pending at once, some out-of-band 5945547Swnj * data may creep in... ick. 5955547Swnj */ 5965547Swnj if (ti->ti_urp <= ti->ti_len) { 5975547Swnj tcp_pulloutofband(so, ti); 5985547Swnj } 5995419Swnj } 6004601Swnj 6014601Swnj /* 6025065Swnj * Process the segment text, merging it into the TCP sequencing queue, 6035065Swnj * and arranging for acknowledgment of receipt if necessary. 6045065Swnj * This process logically involves adjusting tp->rcv_wnd as data 6055065Swnj * is presented to the user (this happens in tcp_usrreq.c, 6065065Swnj * case PRU_RCVD). If a FIN has already been received on this 6075065Swnj * connection then we just ignore the text. 6084601Swnj */ 6095263Swnj if ((ti->ti_len || (tiflags&TH_FIN)) && 6105263Swnj TCPS_HAVERCVDFIN(tp->t_state) == 0) { 6115065Swnj tiflags = tcp_reass(tp, ti); 6125440Swnj if (tcpnodelack == 0) 6135440Swnj tp->t_flags |= TF_DELACK; 6145440Swnj else 6155440Swnj tp->t_flags |= TF_ACKNOW; 6165244Sroot } else { 6174924Swnj m_freem(m); 6185263Swnj tiflags &= ~TH_FIN; 6195244Sroot } 6204601Swnj 6214601Swnj /* 6225263Swnj * If FIN is received ACK the FIN and let the user know 6235263Swnj * that the connection is closing. 6244601Swnj */ 6255263Swnj if (tiflags & TH_FIN) { 6265244Sroot if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { 6275244Sroot socantrcvmore(so); 6285244Sroot tp->t_flags |= TF_ACKNOW; 6295244Sroot tp->rcv_nxt++; 6305244Sroot } 6315065Swnj switch (tp->t_state) { 6324601Swnj 6335065Swnj /* 6345065Swnj * In SYN_RECEIVED and ESTABLISHED STATES 6355065Swnj * enter the CLOSE_WAIT state. 6364884Swnj */ 6375065Swnj case TCPS_SYN_RECEIVED: 6385065Swnj case TCPS_ESTABLISHED: 6395065Swnj tp->t_state = TCPS_CLOSE_WAIT; 6405065Swnj break; 6414884Swnj 6425065Swnj /* 6435085Swnj * If still in FIN_WAIT_1 STATE FIN has not been acked so 6445085Swnj * enter the CLOSING state. 6454884Swnj */ 6465065Swnj case TCPS_FIN_WAIT_1: 6475085Swnj tp->t_state = TCPS_CLOSING; 6485065Swnj break; 6494601Swnj 6505065Swnj /* 6515065Swnj * In FIN_WAIT_2 state enter the TIME_WAIT state, 6525065Swnj * starting the time-wait timer, turning off the other 6535065Swnj * standard timers. 6545065Swnj */ 6555065Swnj case TCPS_FIN_WAIT_2: 6565244Sroot tp->t_state = TCPS_TIME_WAIT; 6575074Swnj tcp_canceltimers(tp); 6585162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 6595244Sroot soisdisconnected(so); 6605065Swnj break; 6615065Swnj 6624884Swnj /* 6635065Swnj * In TIME_WAIT state restart the 2 MSL time_wait timer. 6644884Swnj */ 6655065Swnj case TCPS_TIME_WAIT: 6665162Swnj tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; 6675065Swnj break; 6685085Swnj } 6694601Swnj } 6705267Sroot if (so->so_options & SO_DEBUG) 6715267Sroot tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0); 6725085Swnj 6735085Swnj /* 6745085Swnj * Return any desired output. 6755085Swnj */ 6765085Swnj tcp_output(tp); 6775065Swnj return; 6785085Swnj 6795065Swnj dropafterack: 6805085Swnj /* 6815244Sroot * Generate an ACK dropping incoming segment. 6825085Swnj * Make ACK reflect our state. 6835085Swnj */ 6845085Swnj if (tiflags & TH_RST) 6855085Swnj goto drop; 6865391Swnj tcp_respond(tp, ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK); 6875231Swnj return; 6885085Swnj 6895085Swnj dropwithreset: 6905440Swnj if (om) 6915440Swnj m_free(om); 6925085Swnj /* 6935244Sroot * Generate a RST, dropping incoming segment. 6945085Swnj * Make ACK acceptable to originator of segment. 6955085Swnj */ 6965085Swnj if (tiflags & TH_RST) 6975085Swnj goto drop; 6985085Swnj if (tiflags & TH_ACK) 6995391Swnj tcp_respond(tp, ti, (tcp_seq)0, ti->ti_ack, TH_RST); 7005085Swnj else { 7015085Swnj if (tiflags & TH_SYN) 7025085Swnj ti->ti_len++; 7035391Swnj tcp_respond(tp, ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK); 7045085Swnj } 7055231Swnj return; 7065085Swnj 7075065Swnj drop: 7085085Swnj /* 7095085Swnj * Drop space held by incoming segment and return. 7105085Swnj */ 7115065Swnj m_freem(m); 7125267Sroot return; 7135065Swnj } 7145065Swnj 7155440Swnj tcp_dooptions(tp, om) 7165440Swnj struct tcpcb *tp; 7175440Swnj struct mbuf *om; 7185419Swnj { 7195440Swnj register u_char *cp; 7205440Swnj int opt, optlen, cnt; 7215419Swnj 7225440Swnj cp = mtod(om, u_char *); 7235440Swnj cnt = om->m_len; 7245440Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 7255440Swnj opt = cp[0]; 7265440Swnj if (opt == TCPOPT_EOL) 7275440Swnj break; 7285440Swnj if (opt == TCPOPT_NOP) 7295440Swnj optlen = 1; 7305440Swnj else 7315440Swnj optlen = cp[1]; 7325440Swnj switch (opt) { 7335440Swnj 7345440Swnj default: 7355440Swnj break; 7365440Swnj 7375440Swnj case TCPOPT_MAXSEG: 7385440Swnj if (optlen != 4) 7395440Swnj continue; 7405440Swnj tp->t_maxseg = *(u_short *)(cp + 2); 7415440Swnj #if vax 7425440Swnj tp->t_maxseg = ntohs(tp->t_maxseg); 7435440Swnj #endif 7445440Swnj break; 7455440Swnj 7465440Swnj #ifdef TCPTRUEOOB 7475440Swnj case TCPOPT_WILLOOB: 7485440Swnj tp->t_flags |= TF_DOOOB; 7495440Swnj printf("tp %x dooob\n", tp); 7505440Swnj break; 7515440Swnj 7525440Swnj case TCPOPT_OOBDATA: { 7535440Swnj int seq; 7545547Swnj register struct socket *so = tp->t_inpcb->inp_socket; 7555547Swnj tcp_seq mark; 7565440Swnj 7575547Swnj if (optlen != 8) 7585440Swnj continue; 7595440Swnj seq = cp[2]; 7605440Swnj if (seq < tp->t_iobseq) 7615440Swnj seq += 256; 7625440Swnj printf("oobdata cp[2] %d iobseq %d seq %d\n", cp[2], tp->t_iobseq, seq); 7635440Swnj if (seq - tp->t_iobseq > 128) { 7645440Swnj printf("bad seq\n"); 7655440Swnj tp->t_oobflags |= TCPOOB_OWEACK; 7665440Swnj break; 7675440Swnj } 7685440Swnj tp->t_iobseq = cp[2]; 7695440Swnj tp->t_iobc = cp[3]; 7705547Swnj mark = *(tcp_seq *)(cp + 4); 7715547Swnj #if vax 7725547Swnj mark = ntohl(mark); 7735547Swnj #endif 7745547Swnj so->so_oobmark = so->so_rcv.sb_cc + (mark-tp->rcv_nxt); 7755547Swnj if (so->so_oobmark == 0) 7765547Swnj so->so_state |= SS_RCVATMARK; 7775440Swnj printf("take oob data %x input iobseq now %x\n", tp->t_iobc, tp->t_iobseq); 7785547Swnj sohasoutofband(so); 7795440Swnj break; 7805419Swnj } 7815440Swnj 7825440Swnj case TCPOPT_OOBACK: { 7835440Swnj int seq; 7845440Swnj 7855440Swnj if (optlen != 4) 7865440Swnj continue; 7875440Swnj if (tp->t_oobseq != cp[2]) { 7885440Swnj printf("wrong ack\n"); 7895440Swnj break; 7905440Swnj } 7915440Swnj printf("take oob ack %x and cancel rexmt\n", cp[2]); 7925440Swnj tp->t_oobflags &= ~TCPOOB_NEEDACK; 7935440Swnj tp->t_timer[TCPT_OOBREXMT] = 0; 7945419Swnj break; 7955440Swnj } 7965440Swnj #endif TCPTRUEOOB 7975440Swnj } 7985419Swnj } 7995440Swnj m_free(om); 8005419Swnj } 8015419Swnj 8025419Swnj /* 8035547Swnj * Pull out of band byte out of a segment so 8045547Swnj * it doesn't appear in the user's data queue. 8055547Swnj * It is still reflected in the segment length for 8065547Swnj * sequencing purposes. 8075547Swnj */ 8085547Swnj tcp_pulloutofband(so, ti) 8095547Swnj struct socket *so; 8105547Swnj struct tcpiphdr *ti; 8115547Swnj { 8125547Swnj register struct mbuf *m; 813*6116Swnj int cnt = ti->ti_urp - 1; 8145547Swnj 8155547Swnj m = dtom(ti); 8165547Swnj while (cnt >= 0) { 8175547Swnj if (m->m_len > cnt) { 8185547Swnj char *cp = mtod(m, caddr_t) + cnt; 8195547Swnj struct tcpcb *tp = sototcpcb(so); 8205547Swnj 8215547Swnj tp->t_iobc = *cp; 8225547Swnj tp->t_oobflags |= TCPOOB_HAVEDATA; 8235547Swnj bcopy(cp+1, cp, m->m_len - cnt - 1); 8245547Swnj m->m_len--; 8255547Swnj return; 8265547Swnj } 8275547Swnj cnt -= m->m_len; 8285547Swnj m = m->m_next; 8295547Swnj if (m == 0) 8305547Swnj break; 8315547Swnj } 8325547Swnj panic("tcp_pulloutofband"); 8335547Swnj } 8345547Swnj 8355547Swnj /* 8365065Swnj * Insert segment ti into reassembly queue of tcp with 8375065Swnj * control block tp. Return TH_FIN if reassembly now includes 8385065Swnj * a segment with FIN. 8395065Swnj */ 8405109Swnj tcp_reass(tp, ti) 8415065Swnj register struct tcpcb *tp; 8425065Swnj register struct tcpiphdr *ti; 8435065Swnj { 8445065Swnj register struct tcpiphdr *q; 8455085Swnj struct socket *so = tp->t_inpcb->inp_socket; 8465263Swnj struct mbuf *m; 8475263Swnj int flags; 8485085Swnj COUNT(TCP_REASS); 8495065Swnj 8505065Swnj /* 8515162Swnj * Call with ti==0 after become established to 8525162Swnj * force pre-ESTABLISHED data up to user socket. 8535065Swnj */ 8545162Swnj if (ti == 0) 8555065Swnj goto present; 8564601Swnj 8575065Swnj /* 8585065Swnj * Find a segment which begins after this one does. 8595065Swnj */ 8605065Swnj for (q = tp->seg_next; q != (struct tcpiphdr *)tp; 8615065Swnj q = (struct tcpiphdr *)q->ti_next) 8625065Swnj if (SEQ_GT(q->ti_seq, ti->ti_seq)) 8635065Swnj break; 8644601Swnj 8655065Swnj /* 8665065Swnj * If there is a preceding segment, it may provide some of 8675065Swnj * our data already. If so, drop the data from the incoming 8685065Swnj * segment. If it provides all of our data, drop us. 8695065Swnj */ 8705065Swnj if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { 8715065Swnj register int i; 8725690Swnj q = (struct tcpiphdr *)q->ti_prev; 8735065Swnj /* conversion to int (in i) handles seq wraparound */ 8745065Swnj i = q->ti_seq + q->ti_len - ti->ti_seq; 8755065Swnj if (i > 0) { 8764924Swnj if (i >= ti->ti_len) 8775065Swnj goto drop; 8785065Swnj m_adj(dtom(tp), i); 8795065Swnj ti->ti_len -= i; 8804924Swnj ti->ti_seq += i; 8814601Swnj } 8825065Swnj q = (struct tcpiphdr *)(q->ti_next); 8835065Swnj } 8844601Swnj 8855065Swnj /* 8865065Swnj * While we overlap succeeding segments trim them or, 8875065Swnj * if they are completely covered, dequeue them. 8885065Swnj */ 8895690Swnj while (q != (struct tcpiphdr *)tp) { 8905065Swnj register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; 8915690Swnj if (i <= 0) 8925690Swnj break; 8935065Swnj if (i < q->ti_len) { 8945690Swnj q->ti_seq += i; 8955065Swnj q->ti_len -= i; 8965065Swnj m_adj(dtom(q), i); 8975065Swnj break; 8984601Swnj } 8995065Swnj q = (struct tcpiphdr *)q->ti_next; 9005623Swnj m = dtom(q->ti_prev); 9015065Swnj remque(q->ti_prev); 9025623Swnj m_freem(m); 9035065Swnj } 9044601Swnj 9055065Swnj /* 9065065Swnj * Stick new segment in its place. 9075065Swnj */ 9085065Swnj insque(ti, q->ti_prev); 9094601Swnj 9105065Swnj present: 9115065Swnj /* 9125244Sroot * Present data to user, advancing rcv_nxt through 9135244Sroot * completed sequence space. 9145065Swnj */ 9155263Swnj if (TCPS_HAVERCVDSYN(tp->t_state) == 0) 9165244Sroot return (0); 9174924Swnj ti = tp->seg_next; 9185263Swnj if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) 9195263Swnj return (0); 9205263Swnj if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) 9215263Swnj return (0); 9225263Swnj do { 9235244Sroot tp->rcv_nxt += ti->ti_len; 9245244Sroot flags = ti->ti_flags & TH_FIN; 9254924Swnj remque(ti); 9265263Swnj m = dtom(ti); 9274924Swnj ti = (struct tcpiphdr *)ti->ti_next; 9285263Swnj if (so->so_state & SS_CANTRCVMORE) 9295263Swnj (void) m_freem(m); 9305263Swnj else 9315263Swnj sbappend(&so->so_rcv, m); 9325263Swnj } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); 9335263Swnj sorwakeup(so); 9345065Swnj return (flags); 9355065Swnj drop: 9365065Swnj m_freem(dtom(ti)); 9375263Swnj return (0); 9384601Swnj } 939