X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/473a17a5bf996b2f703cd226ca7ef88ac40bfcdb..4023eed27a3d5dfd1145560a2a8cc42880469c82:/usr/src/sys/netinet/tcp_input.c diff --git a/usr/src/sys/netinet/tcp_input.c b/usr/src/sys/netinet/tcp_input.c index a6a7867234..63ac1ba44b 100644 --- a/usr/src/sys/netinet/tcp_input.c +++ b/usr/src/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* tcp_input.c 1.51 82/01/25 */ +/* tcp_input.c 1.68 82/06/20 */ #include "../h/param.h" #include "../h/systm.h" @@ -7,6 +7,7 @@ #include "../h/socket.h" #include "../h/socketvar.h" #include "../net/in.h" +#include "../net/route.h" #include "../net/in_pcb.h" #include "../net/in_systm.h" #include "../net/if.h" @@ -45,8 +46,8 @@ tcp_input(m0) struct socket *so; int todrop, acked; short ostate; + struct in_addr laddr; -COUNT(TCP_INPUT); /* * Get IP and TCP header together in first mbuf. * Note: IP leaves IP header in first mbuf. @@ -72,12 +73,13 @@ COUNT(TCP_INPUT); ti->ti_next = ti->ti_prev = 0; ti->ti_x1 = 0; ti->ti_len = (u_short)tlen; -#if vax - ti->ti_len = htons(ti->ti_len); +#if vax || pdp11 + ti->ti_len = htons((u_short)ti->ti_len); #endif if (ti->ti_sum = in_cksum(m, len)) { tcpstat.tcps_badsum++; - printf("tcp cksum %x\n", ti->ti_sum); + if (tcpprintfs) + printf("tcp cksum %x\n", ti->ti_sum); goto drop; } } @@ -91,7 +93,8 @@ COUNT(TCP_INPUT); tcpstat.tcps_badoff++; goto drop; } - ti->ti_len = tlen - off; + tlen -= off; + ti->ti_len = tlen; if (off > sizeof (struct tcphdr)) { if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) { tcpstat.tcps_hdrops++; @@ -104,14 +107,22 @@ COUNT(TCP_INPUT); om->m_off = MMINOFF; om->m_len = off - sizeof (struct tcphdr); { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr); - bcopy(op, mtod(om, caddr_t), om->m_len); + bcopy(op, mtod(om, caddr_t), (unsigned)om->m_len); m->m_len -= om->m_len; - bcopy(op+om->m_len, op, m->m_len-sizeof (struct tcpiphdr)); + bcopy(op+om->m_len, op, + (unsigned)(m->m_len-sizeof (struct tcpiphdr))); } } tiflags = ti->ti_flags; -#if vax + /* + * Drop TCP and IP headers. + */ + off += sizeof (struct ip); + m->m_off += off; + m->m_len -= off; + +#if vax || pdp11 /* * Convert TCP protocol specific fields to host format. */ @@ -122,10 +133,12 @@ COUNT(TCP_INPUT); #endif /* - * Locate pcb for segment. + * Locate pcb for segment. On match, update the local + * address stored in the block to reflect anchoring. */ inp = in_pcblookup - (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport); + (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport, + INPLOOKUP_WILDCARD); /* * If the state is CLOSED (i.e., TCB does not exist) then @@ -188,11 +201,18 @@ COUNT(TCP_INPUT); goto drop; tcp_in.sin_addr = ti->ti_src; tcp_in.sin_port = ti->ti_sport; - if (in_pcbconnect(inp, (struct sockaddr *)&tcp_in)) + laddr = inp->inp_laddr; + if (inp->inp_laddr.s_addr == 0) + inp->inp_laddr = ti->ti_dst; + if (in_pcbconnect(inp, (struct sockaddr_in *)&tcp_in)) { + inp->inp_laddr = laddr; goto drop; + } tp->t_template = tcp_template(tp); if (tp->t_template == 0) { in_pcbdisconnect(inp); + inp->inp_laddr = laddr; + tp = 0; goto drop; } tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; @@ -222,8 +242,10 @@ COUNT(TCP_INPUT); SEQ_GT(ti->ti_ack, tp->snd_max))) goto dropwithreset; if (tiflags & TH_RST) { - if (tiflags & TH_ACK) + if (tiflags & TH_ACK) { tcp_drop(tp, ECONNREFUSED); + tp = 0; + } goto drop; } if ((tiflags & TH_SYN) == 0) @@ -276,6 +298,7 @@ trimthenstep6: if (tp->rcv_nxt != ti->ti_seq) goto dropafterack; if (ti->ti_len > 0) { + m_adj(m, ti->ti_len); ti->ti_len = 0; ti->ti_flags &= ~(TH_PUSH|TH_FIN); } @@ -284,10 +307,11 @@ trimthenstep6: * If segment begins before rcv_nxt, drop leading * data (and SYN); if nothing left, just ack. */ - if (SEQ_GT(tp->rcv_nxt, ti->ti_seq)) { - todrop = tp->rcv_nxt - ti->ti_seq; + todrop = tp->rcv_nxt - ti->ti_seq; + if (todrop > 0) { if (tiflags & TH_SYN) { tiflags &= ~TH_SYN; + ti->ti_flags &= ~TH_SYN; ti->ti_seq++; if (ti->ti_urp > 1) ti->ti_urp--; @@ -295,7 +319,8 @@ trimthenstep6: tiflags &= ~TH_URG; todrop--; } - if (todrop > ti->ti_len) + if (todrop > ti->ti_len || + todrop == ti->ti_len && (tiflags&TH_FIN) == 0) goto dropafterack; m_adj(m, todrop); ti->ti_seq += todrop; @@ -304,20 +329,17 @@ trimthenstep6: ti->ti_urp -= todrop; else { tiflags &= ~TH_URG; - /* ti->ti_flags &= ~TH_URG; */ - /* ti->ti_urp = 0; */ + ti->ti_flags &= ~TH_URG; + ti->ti_urp = 0; } - /* tiflags &= ~TH_SYN; */ - /* ti->ti_flags &= ~TH_SYN; */ } /* * If segment ends after window, drop trailing data * (and PUSH and FIN); if nothing left, just ACK. */ - if (SEQ_GT(ti->ti_seq+ti->ti_len, tp->rcv_nxt+tp->rcv_wnd)) { - todrop = - ti->ti_seq+ti->ti_len - (tp->rcv_nxt+tp->rcv_wnd); - if (todrop > ti->ti_len) + todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); + if (todrop > 0) { + if (todrop >= ti->ti_len) goto dropafterack; m_adj(m, -todrop); ti->ti_len -= todrop; @@ -325,6 +347,16 @@ trimthenstep6: } } + /* + * If a segment is received on a connection after the + * user processes are gone, then RST the other end. + */ + if (so->so_state & SS_USERGONE) { + tcp_close(tp); + tp = 0; + goto dropwithreset; + } + /* * If the RST bit is set examine the state: * SYN_RECEIVED STATE: @@ -345,9 +377,14 @@ trimthenstep6: inp->inp_ppcb = 0; tp = tcp_newtcpcb(inp); tp->t_state = TCPS_LISTEN; + inp->inp_faddr.s_addr = 0; + inp->inp_fport = 0; + inp->inp_laddr.s_addr = 0; /* not quite right */ + tp = 0; goto drop; } tcp_drop(tp, ECONNREFUSED); + tp = 0; goto drop; case TCPS_ESTABLISHED: @@ -355,12 +392,14 @@ trimthenstep6: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT: tcp_drop(tp, ECONNRESET); + tp = 0; goto drop; case TCPS_CLOSING: case TCPS_LAST_ACK: case TCPS_TIME_WAIT: tcp_close(tp); + tp = 0; goto drop; } @@ -370,6 +409,7 @@ trimthenstep6: */ if (tiflags & TH_SYN) { tcp_drop(tp, ECONNRESET); + tp = 0; goto dropwithreset; } @@ -427,42 +467,44 @@ trimthenstep6: if (SEQ_GT(ti->ti_ack, tp->snd_max)) goto dropafterack; acked = ti->ti_ack - tp->snd_una; + + /* + * If transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + */ + if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) { + if (tp->t_srtt == 0) + tp->t_srtt = tp->t_rtt; + else + tp->t_srtt = + tcp_alpha * tp->t_srtt + + (1 - tcp_alpha) * tp->t_rtt; +/* printf("rtt %d srtt*100 now %d\n", tp->t_rtt, (int)(tp->t_srtt*100)); */ + tp->t_rtt = 0; + } + if (ti->ti_ack == tp->snd_max) tp->t_timer[TCPT_REXMT] = 0; else { TCPT_RANGESET(tp->t_timer[TCPT_REXMT], tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX); - tp->t_rtt = 0; + tp->t_rtt = 1; tp->t_rxtshift = 0; } if (acked > so->so_snd.sb_cc) { sbdrop(&so->so_snd, so->so_snd.sb_cc); tp->snd_wnd -= so->so_snd.sb_cc; } else { - sbdrop(&so->so_snd.sb_cc, acked); + sbdrop(&so->so_snd, acked); tp->snd_wnd -= acked; acked = 0; } - if (so->so_snd.sb_flags & SB_WAIT) + if ((so->so_snd.sb_flags & SB_WAIT) || so->so_snd.sb_sel) sowwakeup(so); tp->snd_una = ti->ti_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; - /* - * If transmit timer is running and timed sequence - * number was acked, update smoothed round trip time. - */ - if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) { - if (tp->t_srtt == 0) - tp->t_srtt = tp->t_rtt; - else - tp->t_srtt = - tcp_alpha * tp->t_srtt + - (1 - tcp_alpha) * tp->t_rtt; - tp->t_rtt = 0; - } - switch (tp->t_state) { /* @@ -471,8 +513,15 @@ trimthenstep6: * then enter FIN_WAIT_2. */ case TCPS_FIN_WAIT_1: - if (ourfinisacked) + if (ourfinisacked) { + /* + * If we can't receive any more + * data, then closing user can proceed. + */ + if (so->so_state & SS_CANTRCVMORE) + soisdisconnected(so); tp->t_state = TCPS_FIN_WAIT_2; + } break; /* @@ -497,8 +546,10 @@ trimthenstep6: * and return. */ case TCPS_LAST_ACK: - if (ourfinisacked) + if (ourfinisacked) { tcp_close(tp); + tp = 0; + } goto drop; /* @@ -520,9 +571,6 @@ step6: if (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd)) { -/* -printf("wl1 %x seq %x wl2 %x ack %x win %x wnd %x\n", tp->snd_wl1, ti->ti_seq, tp->snd_wl2, ti->ti_ack, ti->ti_win, tp->snd_wnd); -*/ tp->snd_wnd = ti->ti_win; tp->snd_wl1 = ti->ti_seq; tp->snd_wl2 = ti->ti_ack; @@ -574,9 +622,6 @@ printf("wl1 %x seq %x wl2 %x ack %x win %x wnd %x\n", tp->snd_wl1, ti->ti_seq, t */ if ((ti->ti_len || (tiflags&TH_FIN)) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { - off += sizeof (struct ip); /* drop IP header */ - m->m_off += off; - m->m_len -= off; tiflags = tcp_reass(tp, ti); if (tcpnodelack == 0) tp->t_flags |= TF_DELACK; @@ -642,22 +687,25 @@ printf("wl1 %x seq %x wl2 %x ack %x win %x wnd %x\n", tp->snd_wl1, ti->ti_seq, t /* * Return any desired output. */ - tcp_output(tp); + (void) tcp_output(tp); return; dropafterack: /* - * Generate an ACK dropping incoming segment. - * Make ACK reflect our state. + * Generate an ACK dropping incoming segment if it occupies + * sequence space, where the ACK reflects our state. */ - if (tiflags & TH_RST) + if ((tiflags&TH_RST) || + tlen == 0 && (tiflags&(TH_SYN|TH_FIN)) == 0) goto drop; + if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) + tcp_trace(TA_RESPOND, ostate, tp, &tcp_saveti, 0); tcp_respond(tp, ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK); return; dropwithreset: if (om) - m_free(om); + (void) m_free(om); /* * Generate a RST, dropping incoming segment. * Make ACK acceptable to originator of segment. @@ -669,7 +717,8 @@ dropwithreset: else { if (tiflags & TH_SYN) ti->ti_len++; - tcp_respond(tp, ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK); + tcp_respond(tp, ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, + TH_RST|TH_ACK); } return; @@ -677,6 +726,8 @@ drop: /* * Drop space held by incoming segment and return. */ + if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0); m_freem(m); return; } @@ -707,8 +758,8 @@ tcp_dooptions(tp, om) if (optlen != 4) continue; tp->t_maxseg = *(u_short *)(cp + 2); -#if vax - tp->t_maxseg = ntohs(tp->t_maxseg); +#if vax || pdp11 + tp->t_maxseg = ntohs((u_short)tp->t_maxseg); #endif break; @@ -737,7 +788,7 @@ printf("bad seq\n"); tp->t_iobseq = cp[2]; tp->t_iobc = cp[3]; mark = *(tcp_seq *)(cp + 4); -#if vax +#if vax || pdp11 mark = ntohl(mark); #endif so->so_oobmark = so->so_rcv.sb_cc + (mark-tp->rcv_nxt); @@ -765,7 +816,7 @@ printf("take oob ack %x and cancel rexmt\n", cp[2]); #endif TCPTRUEOOB } } - m_free(om); + (void) m_free(om); } /* @@ -779,7 +830,7 @@ tcp_pulloutofband(so, ti) struct tcpiphdr *ti; { register struct mbuf *m; - int cnt = sizeof (struct tcpiphdr) + ti->ti_urp - 1; + int cnt = ti->ti_urp - 1; m = dtom(ti); while (cnt >= 0) { @@ -789,7 +840,7 @@ tcp_pulloutofband(so, ti) tp->t_iobc = *cp; tp->t_oobflags |= TCPOOB_HAVEDATA; - bcopy(cp+1, cp, m->m_len - cnt - 1); + bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1)); m->m_len--; return; } @@ -814,7 +865,6 @@ tcp_reass(tp, ti) struct socket *so = tp->t_inpcb->inp_socket; struct mbuf *m; int flags; -COUNT(TCP_REASS); /* * Call with ti==0 after become established to @@ -838,7 +888,7 @@ COUNT(TCP_REASS); */ if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { register int i; - q = (struct tcpiphdr *)(q->ti_prev); + q = (struct tcpiphdr *)q->ti_prev; /* conversion to int (in i) handles seq wraparound */ i = q->ti_seq + q->ti_len - ti->ti_seq; if (i > 0) { @@ -855,10 +905,12 @@ COUNT(TCP_REASS); * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ - while (q != (struct tcpiphdr *)tp && - SEQ_GT(ti->ti_seq + ti->ti_len, q->ti_seq)) { + while (q != (struct tcpiphdr *)tp) { register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; + if (i <= 0) + break; if (i < q->ti_len) { + q->ti_seq += i; q->ti_len -= i; m_adj(dtom(q), i); break; @@ -893,7 +945,7 @@ present: m = dtom(ti); ti = (struct tcpiphdr *)ti->ti_next; if (so->so_state & SS_CANTRCVMORE) - (void) m_freem(m); + m_freem(m); else sbappend(&so->so_rcv, m); } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);