sbappend(&so->so_rcv, q->ipqe_m);
sbappendstream(&so->so_rcv, q->ipqe_m);
tcp_reass(tp, th, m, tlen)	struct tcpcb *tp;	struct tcphdr *th;	struct mbuf *m;	int *tlen;{	struct ipqent *p, *q, *nq, *tiqe;	struct socket *so = tp->t_inpcb->inp_socket;	int flags;	/*	 * Call with th==0 after become established to	 * force pre-ESTABLISHED data up to user socket.	 */	if (th == 0)		goto present;	/*	 * Allocate a new queue entry, before we throw away any data.	 * If we can't, just drop the packet.  XXX	 */	tiqe =  pool_get(&ipqent_pool, PR_NOWAIT);	if (tiqe == NULL) {		tcpstat.tcps_rcvmemdrop++;		m_freem(m);		return (0);	}	/*	 * Find a segment which begins after this one does.	 */	for (p = NULL, q = tp->segq.lh_first; q != NULL;	    p = q, q = q->ipqe_q.le_next)		if (SEQ_GT(q->ipqe_tcp->th_seq, th->th_seq))			break;	/*	 * If there is a preceding segment, it may provide some of	 * our data already.  If so, drop the data from the incoming	 * segment.  If it provides all of our data, drop us.	 */	if (p != NULL) {		struct tcphdr *phdr = p->ipqe_tcp;		int i;		/* conversion to int (in i) handles seq wraparound */		i = phdr->th_seq + phdr->th_reseqlen - th->th_seq;		if (i > 0) {		        if (i >= *tlen) {				tcpstat.tcps_rcvduppack++;				tcpstat.tcps_rcvdupbyte += *tlen;				m_freem(m);				pool_put(&ipqent_pool, tiqe);				return (0);			}			m_adj(m, i);			*tlen -= i;			th->th_seq += i;		}	}	tcpstat.tcps_rcvoopack++;	tcpstat.tcps_rcvoobyte += *tlen;	/*	 * While we overlap succeeding segments trim them or,	 * if they are completely covered, dequeue them.	 */	for (; q != NULL; q = nq) {		struct tcphdr *qhdr = q->ipqe_tcp;		int i = (th->th_seq + *tlen) - qhdr->th_seq;		if (i <= 0)			break;		if (i < qhdr->th_reseqlen) {			qhdr->th_seq += i;			qhdr->th_reseqlen -= i;			m_adj(q->ipqe_m, i);			break;		}		nq = q->ipqe_q.le_next;		m_freem(q->ipqe_m);		LIST_REMOVE(q, ipqe_q);		pool_put(&ipqent_pool, q);	}	/* Insert the new fragment queue entry into place. */	tiqe->ipqe_m = m;	th->th_reseqlen = *tlen;	tiqe->ipqe_tcp = th;	if (p == NULL) {		LIST_INSERT_HEAD(&tp->segq, tiqe, ipqe_q);	} else {		LIST_INSERT_AFTER(p, tiqe, ipqe_q);	}present:	/*	 * Present data to user, advancing rcv_nxt through	 * completed sequence space.	 */	if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)		return (0);	q = tp->segq.lh_first;	if (q == NULL || q->ipqe_tcp->th_seq != tp->rcv_nxt)		return (0);	if (tp->t_state == TCPS_SYN_RECEIVED && q->ipqe_tcp->th_reseqlen)		return (0);	do {		tp->rcv_nxt += q->ipqe_tcp->th_reseqlen;		flags = q->ipqe_tcp->th_flags & TH_FIN;		nq = q->ipqe_q.le_next;		LIST_REMOVE(q, ipqe_q);		ND6_HINT(tp);		if (so->so_state & SS_CANTRCVMORE)			m_freem(q->ipqe_m);		else			sbappend(&so->so_rcv, q->ipqe_m);		pool_put(&ipqent_pool, q);		q = nq;	} while (q != NULL && q->ipqe_tcp->th_seq == tp->rcv_nxt);	sorwakeup(so);	return (flags);}