- while (n->t_seq == tp->rcv_nxt) {
- /* present data belongs here */
- tp->rcv_nxt += n->t_len;
- n = n->t_next;
- if (n == (struct th *)tp)
- break;
- }
- tp->tc_flags |= (TC_ACK_DUE|TC_NET_KEEP);
- }
-notext:
-urgeolfin:
-/* urg */
- if (n->th_flags&TH_URG) {
- unsigned urgent;
-
- urgent = n->t_urp + n->t_seq;
- if (tp->rcv_nxt < urgent) {
- if (tp->rcv_urp <= tp->rcv_nxt)
- to_user(tp->t_ucb, UURGENT);
- tp->rcv_urp = urgent;
- }
- }
-/* eol */
- if ((n->th_flags&TH_EOL) &&
- (tp->tc_flags&TC_DROPPED_TXT) == 0 &&
- tp->t_rcv_prev != (struct th *)tp) {
- /* mark last mbuf */
- m = dtom(tp->t_rcv_prev);
- if (m != NULL) {
- while (m->m_next != NULL)
- m = m->m_next;
- m->m_act =
- (struct mbuf *)(m->m_off + m->m_len - 1);
- }
- }
-ctlonly:
-/* fin */
- if ((n->th_flags&TH_FIN) && (tp->tc_flags&TC_DROPPED_TXT) == 0) {
- seq_t last;
-
- if ((tp->tc_flags&TC_FIN_RCVD) == 0) {
- /* do we really have fin ? */
- last = firstempty(tp);
- if (tp->t_rcv_prev == (struct th *)tp ||
- last == t_end(tp->t_rcv_prev)) {
- tp->tc_flags |= TC_FIN_RCVD;
- netwakeup(tp->t_ucb); /* poke */
- }
- if ((tp->tc_flags&TC_FIN_RCVD) &&
- tp->rcv_nxt >= last) {
- tp->rcv_nxt = last + 1; /* fin seq */
- tp->tc_flags |= TC_ACK_DUE;
- }
- } else
- tp->tc_flags |= TC_ACK_DUE;
- }
-
-/* respond */
- sent = 0;
- if (tp->tc_flags&TC_ACK_DUE)
- sent = tcp_sndctl(tp);
- else if (tp->tc_flags&TC_NEW_WINDOW) {
- seq_t last = tp->snd_off;
- for (m = tp->t_ucb->uc_sbuf; m != NULL; m = m->m_next) /*###*/
- last += m->m_len; /*###*/
- if (tp->snd_nxt <= last || (tp->tc_flags&TC_SND_FIN))
- sent = tcp_send(tp);
- }
-
-/* set for retrans */
- if (!sent && tp->snd_una < tp->snd_nxt &&
- (tp->tc_flags&TC_CANCELLED)) {
- tp->t_rexmt = tp->t_xmtime;
- tp->t_rexmttl = T_REXMTTL;
- tp->t_rexmt_val = tp->t_rtl_val = tp->snd_lst;
- tp->tc_flags &= ~TC_CANCELLED;
- }
-/* present data to user */
- { register struct mbuf **mp;
- register struct ucb *up = tp->t_ucb;
- seq_t ready;
-
- /* connection must be synced and data available for user */
- if ((tp->tc_flags&TC_SYN_ACKED) == 0)
- return;
- up = tp->t_ucb;
- mp = &up->uc_rbuf;
- while (*mp)
- mp = &(*mp)->m_next;
- n = tp->t_rcv_next;
- /* SHOULD PACK DATA IN HERE */
- while (n != (struct th *)tp && n->t_seq < tp->rcv_nxt) {
- remque(n);
- m = dtom(n);
- up->uc_rcc += n->t_len;
- tp->seqcnt -= n->t_len;
- if (tp->seqcnt < 0) panic("present_data");
- n = n->t_next;
- while (m) {
- if (m->m_len == 0) {
- MFREE(m, *mp);
- } else {
- *mp = m;
- mp = &m->m_next;
- }
- m = *mp;
- }
- }
- if (up->uc_rcc != 0)
- netwakeup(up);
- if ((tp->tc_flags&TC_FIN_RCVD) && /* ### */
- (tp->tc_flags&TC_USR_CLOSED) == 0 && /* ### */
- rcv_empty(tp)) /* ### */
- to_user(up, UCLOSED); /* ### */
- }
+ if (TCPS_HAVERCVDSYN(tp->t_state) == 0)
+ return (0);
+ ti = tp->seg_next;
+ if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt)
+ return (0);
+ if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len)
+ return (0);
+ do {
+ tp->rcv_nxt += ti->ti_len;
+ flags = ti->ti_flags & TH_FIN;
+ remque(ti);
+ m = dtom(ti);
+ ti = (struct tcpiphdr *)ti->ti_next;
+ if (so->so_state & SS_CANTRCVMORE)
+ (void) m_freem(m);
+ else
+ sbappend(&so->so_rcv, m);
+ } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
+ sorwakeup(so);
+ return (flags);
+drop:
+ m_freem(dtom(ti));
+ return (0);