Example #1
0
/*
 * Free a fragment reassembly header and all
 * associated datagrams.
 */
void ip_freef(struct ipq *fp)
{
	struct ipasfrag *q, *p;

	for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp;
	    q = p) {
		p = (struct ipasfrag *) q->ipf_next;
		ip_deq(q);
		m_freem(dtom(q));
	}
	remque_32(fp);
	(void) m_free(dtom(fp));
}
Example #2
0
static int
tcp_reass(register struct tcpcb *tp, register struct tcpiphdr *ti,
          struct mbuf *m)
{
	register struct tcpiphdr *q;
	struct socket *so = tp->t_socket;
	int flags;

	/*
	 * Call with ti==0 after become established to
	 * force pre-ESTABLISHED data up to user socket.
	 */
	if (ti == 0)
		goto present;

	/*
	 * Find a segment which begins after this one does.
	 */
	for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp;
	    q = (struct tcpiphdr *)q->ti_next)
		if (SEQ_GT(q->ti_seq, ti->ti_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 ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) {
		register int i;
		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) {
			if (i >= ti->ti_len) {
				STAT(tcpstat.tcps_rcvduppack++);
				STAT(tcpstat.tcps_rcvdupbyte += ti->ti_len);
				m_freem(m);
				/*
				 * Try to present any queued data
				 * at the left window edge to the user.
				 * This is needed after the 3-WHS
				 * completes.
				 */
				goto present;   /* ??? */
			}
			m_adj(m, i);
			ti->ti_len -= i;
			ti->ti_seq += i;
		}
		q = (struct tcpiphdr *)(q->ti_next);
	}
	STAT(tcpstat.tcps_rcvoopack++);
	STAT(tcpstat.tcps_rcvoobyte += ti->ti_len);
	REASS_MBUF(ti) = (mbufp_32) m;		/* XXX */

	/*
	 * While we overlap succeeding segments trim them or,
	 * if they are completely covered, dequeue them.
	 */
	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((struct mbuf *) REASS_MBUF(q), i);
			break;
		}
		q = (struct tcpiphdr *)q->ti_next;
		m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev);
		remque_32((void *)(q->ti_prev));
		m_freem(m);
	}

	/*
	 * Stick new segment in its place.
	 */
	insque_32(ti, (void *)(q->ti_prev));

present:
	/*
	 * Present data to user, advancing rcv_nxt through
	 * completed sequence space.
	 */
	if (!TCPS_HAVEESTABLISHED(tp->t_state))
		return (0);
	ti = (struct tcpiphdr *) 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_32(ti);
		m = (struct mbuf *) REASS_MBUF(ti); /* XXX */
		ti = (struct tcpiphdr *)ti->ti_next;
/*		if (so->so_state & SS_FCANTRCVMORE) */
		if (so->so_state & SS_FCANTSENDMORE)
			m_freem(m);
		else {
			if (so->so_emu) {
				if (tcp_emu(so,m)) sbappend(so, m);
			} else
				sbappend(so, m);
		}
	} while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
/*	sorwakeup(so); */
	return (flags);
}
Example #3
0
/*
 * Take incoming datagram fragment and try to
 * reassemble it into whole datagram.  If a chain for
 * reassembly of this datagram already exists, then it
 * is given as fp; otherwise have to make a chain.
 */
struct ip *ip_reass(struct ipasfrag *ip, struct ipq *fp)
{
	struct mbuf *m = dtom(ip);
	struct ipasfrag *q;
	int hlen = ip->ip_hl << 2;
	int i, next;
	
	DEBUG_CALL("ip_reass");
	DEBUG_ARG("ip = %lx", (long)ip);
	DEBUG_ARG("fp = %lx", (long)fp);
	DEBUG_ARG("m = %lx", (long)m);

	/*
	 * Presence of header sizes in mbufs
	 * would confuse code below.
         * Fragment m_data is concatenated.
	 */
	m->m_data += hlen;
	m->m_len -= hlen;

	/*
	 * If first fragment to arrive, create a reassembly queue.
	 */
	if (fp == 0) {
	  struct mbuf *t;
	  if ((t = m_get()) == NULL) goto dropfrag;
	  fp = mtod(t, struct ipq *);
	  insque_32(fp, &ipq);
	  fp->ipq_ttl = IPFRAGTTL;
	  fp->ipq_p = ip->ip_p;
	  fp->ipq_id = ip->ip_id;
	  fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp;
	  fp->ipq_src = ((struct ip *)ip)->ip_src;
	  fp->ipq_dst = ((struct ip *)ip)->ip_dst;
	  q = (struct ipasfrag *)fp;
	  goto insert;
	}
	
	/*
	 * Find a segment which begins after this one does.
	 */
	for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp;
	    q = (struct ipasfrag *)q->ipf_next)
		if (q->ip_off > ip->ip_off)
			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 (q->ipf_prev != (ipasfragp_32)fp) {
		i = ((struct ipasfrag *)(q->ipf_prev))->ip_off +
		  ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off;
		if (i > 0) {
			if (i >= ip->ip_len)
				goto dropfrag;
			m_adj(dtom(ip), i);
			ip->ip_off += i;
			ip->ip_len -= i;
		}
	}

	/*
	 * While we overlap succeeding segments trim them or,
	 * if they are completely covered, dequeue them.
	 */
	while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
		i = (ip->ip_off + ip->ip_len) - q->ip_off;
		if (i < q->ip_len) {
			q->ip_len -= i;
			q->ip_off += i;
			m_adj(dtom(q), i);
			break;
		}
		q = (struct ipasfrag *) q->ipf_next;
		m_freem(dtom((struct ipasfrag *) q->ipf_prev));
		ip_deq((struct ipasfrag *) q->ipf_prev);
	}

insert:
	/*
	 * Stick new segment in its place;
	 * check for complete reassembly.
	 */
	ip_enq(ip, (struct ipasfrag *) q->ipf_prev);
	next = 0;
	for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp;
	     q = (struct ipasfrag *) q->ipf_next) {
		if (q->ip_off != next)
			return (0);
		next += q->ip_len;
	}
	if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1)
		return (0);

	/*
	 * Reassembly is complete; concatenate fragments.
	 */
	q = (struct ipasfrag *) fp->ipq_next;
	m = dtom(q);

	q = (struct ipasfrag *) q->ipf_next;
	while (q != (struct ipasfrag *)fp) {
	  struct mbuf *t;
	  t = dtom(q);
	  q = (struct ipasfrag *) q->ipf_next;
	  m_cat(m, t);
	}

	/*
	 * Create header for new ip packet by
	 * modifying header of first packet;
	 * dequeue and discard fragment reassembly header.
	 * Make header visible.
	 */
	ip = (struct ipasfrag *) fp->ipq_next;

	/*
	 * If the fragments concatenated to an mbuf that's
	 * bigger than the total size of the fragment, then and
	 * m_ext buffer was alloced. But fp->ipq_next points to
	 * the old buffer (in the mbuf), so we must point ip
	 * into the new buffer.
	 */
	if (m->m_flags & M_EXT) {
	  int delta;
	  delta = (char *)ip - m->m_dat;
	  ip = (struct ipasfrag *)(m->m_ext + delta);
	}

	/* DEBUG_ARG("ip = %lx", (long)ip); 
	 * ip=(struct ipasfrag *)m->m_data; */

	ip->ip_len = next;
	ip->ipf_mff &= ~1;
	((struct ip *)ip)->ip_src = fp->ipq_src;
	((struct ip *)ip)->ip_dst = fp->ipq_dst;
	remque_32(fp);
	(void) m_free(dtom(fp));
	m = dtom(ip);
	m->m_len += (ip->ip_hl << 2);
	m->m_data -= (ip->ip_hl << 2);

	return ((struct ip *)ip);

dropfrag:
	ipstat.ips_fragdropped++;
	m_freem(m);
	return (0);
}