示例#1
0
/*
 * Insert IP options into preformed packet.  Adjust IP destination as
 * required for IP source routing, as indicated by a non-zero in_addr at the
 * start of the options.
 *
 * XXX This routine assumes that the packet has no options in place.
 */
struct mbuf *
ip_insertoptions(struct mbuf *m, struct mbuf *opt, int *phlen)
{
	struct ipoption *p = mtod(opt, struct ipoption *);
	struct mbuf *n;
	struct ip *ip = mtod(m, struct ip *);
	unsigned optlen;

	optlen = opt->m_len - sizeof(p->ipopt_dst);
	if (optlen + ntohs(ip->ip_len) > IP_MAXPACKET) {
		*phlen = 0;
		return (m);		/* XXX should fail */
	}
	if (p->ipopt_dst.s_addr)
		ip->ip_dst = p->ipopt_dst;
	if (!M_WRITABLE(m) || M_LEADINGSPACE(m) < optlen) {
		n = m_gethdr(M_NOWAIT, MT_DATA);
		if (n == NULL) {
			*phlen = 0;
			return (m);
		}
		m_move_pkthdr(n, m);
		n->m_pkthdr.rcvif = NULL;
		n->m_pkthdr.len += optlen;
		m->m_len -= sizeof(struct ip);
		m->m_data += sizeof(struct ip);
		n->m_next = m;
		m = n;
		m->m_len = optlen + sizeof(struct ip);
		m->m_data += max_linkhdr;
		bcopy(ip, mtod(m, void *), sizeof(struct ip));
	} else {
示例#2
0
/*
 * Defragment an mbuf chain, returning at most maxfrags separate
 * mbufs+clusters.  If this is not possible NULL is returned and
 * the original mbuf chain is left in it's present (potentially
 * modified) state.  We use two techniques: collapsing consecutive
 * mbufs and replacing consecutive mbufs by a cluster.
 *
 * NB: this should really be named m_defrag but that name is taken
 */
struct mbuf *
m_collapse(struct mbuf *m0, int how, int maxfrags)
{
	struct mbuf *m, *n, *n2, **prev;
	u_int curfrags;

	/*
	 * Calculate the current number of frags.
	 */
	curfrags = 0;
	for (m = m0; m != NULL; m = m->m_next)
		curfrags++;
	/*
	 * First, try to collapse mbufs.  Note that we always collapse
	 * towards the front so we don't need to deal with moving the
	 * pkthdr.  This may be suboptimal if the first mbuf has much
	 * less data than the following.
	 */
	m = m0;
again:
	for (;;) {
		n = m->m_next;
		if (n == NULL)
			break;
		if (M_WRITABLE(m) &&
		    n->m_len < M_TRAILINGSPACE(m)) {
			bcopy(mtod(n, void *), mtod(m, char *) + m->m_len,
				n->m_len);
			m->m_len += n->m_len;
			m->m_next = n->m_next;
			m_free(n);
			if (--curfrags <= maxfrags)
				return m0;
		} else
示例#3
0
/*
 * Append the data in mbuf chain (m) into the socket buffer sb following mbuf
 * (n).  If (n) is NULL, the buffer is presumed empty.
 *
 * When the data is compressed, mbufs in the chain may be handled in one of
 * three ways:
 *
 * (1) The mbuf may simply be dropped, if it contributes nothing (no data, no
 *     record boundary, and no change in data type).
 *
 * (2) The mbuf may be coalesced -- i.e., data in the mbuf may be copied into
 *     an mbuf already in the socket buffer.  This can occur if an
 *     appropriate mbuf exists, there is room, and no merging of data types
 *     will occur.
 *
 * (3) The mbuf may be appended to the end of the existing mbuf chain.
 *
 * If any of the new mbufs is marked as M_EOR, mark the last mbuf appended as
 * end-of-record.
 */
void
sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n)
{
	int eor = 0;
	struct mbuf *o;

	SOCKBUF_LOCK_ASSERT(sb);

	while (m) {
		eor |= m->m_flags & M_EOR;
		if (m->m_len == 0 &&
		    (eor == 0 ||
		     (((o = m->m_next) || (o = n)) &&
		      o->m_type == m->m_type))) {
			if (sb->sb_lastrecord == m)
				sb->sb_lastrecord = m->m_next;
			m = m_free(m);
			continue;
		}
		if (n && (n->m_flags & M_EOR) == 0 &&
		    M_WRITABLE(n) &&
		    ((sb->sb_flags & SB_NOCOALESCE) == 0) &&
		    m->m_len <= M_TRAILINGSPACE(n) &&
		    n->m_type == m->m_type) {
			if (n->m_flags & M_HOLE) {
				n->m_len += m->m_len;
				sb->sb_cc += m->m_len;
				m = m_free(m);
				continue;
			} else if (m->m_len <= MCLBYTES / 4) { /* XXX: Don't copy too much */
				bcopy(mtod(m, caddr_t),
				      mtod(n, caddr_t) + n->m_len,
				      (unsigned)m->m_len);
				n->m_len += m->m_len;
				sb->sb_cc += m->m_len;
				if (m->m_type != MT_DATA &&
				    m->m_type != MT_OOBDATA)
				/* XXX: Probably don't need.*/
					sb->sb_ctl += m->m_len;
				m = m_free(m);
				continue;
			}
		}
		if (n)
			n->m_next = m;
		else
			sb->sb_mb = m;
		sb->sb_mbtail = m;
		sballoc(sb, m);
		n = m;
		m->m_flags &= ~M_EOR;
		m = m->m_next;
		n->m_next = 0;
	}
	if (eor) {
		KASSERT(n != NULL, ("sbcompress: eor && n == NULL"));
		n->m_flags |= eor;
	}
	SBLASTMBUFCHK(sb);
}
示例#4
0
m_megapullup(PNATState pData, struct mbuf *m, int len)
#endif
{
    struct mbuf *mcl;

    if (len > m->m_pkthdr.len)
        goto bad;

    /* Do not reallocate packet if it is sequentional,
     * writable and has some extra space for expansion.
     * XXX: Constant 100bytes is completely empirical. */
#define RESERVE 100
    if (m->m_next == NULL && M_WRITABLE(m) && M_TRAILINGSPACE(m) >= RESERVE)
        return (m);

    if (len <= MCLBYTES - RESERVE) {
#ifndef VBOX
        mcl = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
#else
        mcl = m_getcl(pData, M_DONTWAIT, MT_DATA, M_PKTHDR);
#endif
    } else if (len < MJUM16BYTES) {
        int size;
        if (len <= MJUMPAGESIZE - RESERVE) {
            size = MJUMPAGESIZE;
        } else if (len <= MJUM9BYTES - RESERVE) {
            size = MJUM9BYTES;
        } else {
            size = MJUM16BYTES;
        };
#ifndef VBOX
        mcl = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size);
#else
        mcl = m_getjcl(pData, M_DONTWAIT, MT_DATA, M_PKTHDR, size);
#endif
    } else {
        goto bad;
    }
    if (mcl == NULL)
        goto bad;

    m_move_pkthdr(mcl, m);
    m_copydata(m, 0, len, mtod(mcl, caddr_t));
    mcl->m_len = mcl->m_pkthdr.len = len;
#ifndef VBOX
    m_freem(m);
#else
    m_freem(pData, m);
#endif

    return (mcl);
bad:
#ifndef VBOX
    m_freem(m);
#else
    m_freem(pData, m);
#endif
    return (NULL);
}
示例#5
0
static int
nicvf_if_transmit(struct ifnet *ifp, struct mbuf *mbuf)
{
	struct nicvf *nic = if_getsoftc(ifp);
	struct queue_set *qs = nic->qs;
	struct snd_queue *sq;
	struct mbuf *mtmp;
	int qidx;
	int err = 0;


	if (__predict_false(qs == NULL)) {
		panic("%s: missing queue set for %s", __func__,
		    device_get_nameunit(nic->dev));
	}

	/* Select queue */
	if (M_HASHTYPE_GET(mbuf) != M_HASHTYPE_NONE)
		qidx = mbuf->m_pkthdr.flowid % qs->sq_cnt;
	else
		qidx = curcpu % qs->sq_cnt;

	sq = &qs->sq[qidx];

	if (mbuf->m_next != NULL &&
	    (mbuf->m_pkthdr.csum_flags &
	    (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP)) != 0) {
		if (M_WRITABLE(mbuf) == 0) {
			mtmp = m_dup(mbuf, M_NOWAIT);
			m_freem(mbuf);
			if (mtmp == NULL)
				return (ENOBUFS);
			mbuf = mtmp;
		}
	}

	err = drbr_enqueue(ifp, sq->br, mbuf);
	if (((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
	    IFF_DRV_RUNNING) || !nic->link_up || (err != 0)) {
		/*
		 * Try to enqueue packet to the ring buffer.
		 * If the driver is not active, link down or enqueue operation
		 * failed, return with the appropriate error code.
		 */
		return (err);
	}

	if (NICVF_TX_TRYLOCK(sq) != 0) {
		err = nicvf_xmit_locked(sq);
		NICVF_TX_UNLOCK(sq);
		return (err);
	} else
		taskqueue_enqueue(sq->snd_taskq, &sq->snd_task);

	return (0);
}
示例#6
0
/*
 * Concatenate mbuf chain n to m.
 * Both chains must be of the same type (e.g. MT_DATA).
 * Any m_pkthdr is not updated.
 */
void
m_cat(struct mbuf *m, struct mbuf *n)
{
	while (m->m_next)
		m = m->m_next;
	while (n) {
		if (!M_WRITABLE(m) ||
		    M_TRAILINGSPACE(m) < n->m_len) {
			/* just join the two chains */
			m->m_next = n;
			return;
		}
		/* splat the data from one into the other */
		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
		    (u_int)n->m_len);
		m->m_len += n->m_len;
		n = m_free(n);
	}
}
示例#7
0
文件: alias.c 项目: ChaosJohn/freebsd
/*
 * m_megapullup() - this function is a big hack.
 * Thankfully, it's only used in ng_nat and ipfw+nat.
 *
 * It allocates an mbuf with cluster and copies the specified part of the chain
 * into cluster, so that it is all contiguous and can be accessed via a plain
 * (char *) pointer. This is required, because libalias doesn't know how to
 * handle mbuf chains.
 *
 * On success, m_megapullup returns an mbuf (possibly with cluster) containing
 * the input packet, on failure NULL. The input packet is always consumed.
 */
struct mbuf *
m_megapullup(struct mbuf *m, int len) {
	struct mbuf *mcl;

	if (len > m->m_pkthdr.len)
		goto bad;

	if (m->m_next == NULL && M_WRITABLE(m))
		return (m);

	mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
	if (mcl == NULL)
		goto bad;
	m_align(mcl, len);
	m_move_pkthdr(mcl, m);
	m_copydata(m, 0, len, mtod(mcl, caddr_t));
	mcl->m_len = mcl->m_pkthdr.len = len;
	m_freem(m);

	return (mcl);
bad:
	m_freem(m);
	return (NULL);
}
示例#8
0
/*
 * Compress mbuf chain m into the socket buffer sb following mbuf tailm.
 * If tailm is null, the buffer is presumed empty.  Also, as a side-effect,
 * increment the sockbuf counts for each mbuf in the chain.
 */
void
sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *tailm)
{
	int eor = 0;
	struct mbuf *free_chain = NULL;

	mbuftrackid(m, 23);

	sbcheck(sb);
	while (m) {
		struct mbuf *o;

		eor |= m->m_flags & M_EOR;
		/*
		 * Disregard empty mbufs as long as we don't encounter
		 * an end-of-record or there is a trailing mbuf of
		 * the same type to propagate the EOR flag to.
		 *
		 * Defer the m_free() call because it can block and break
		 * the atomicy of the sockbuf.
		 */
		if (m->m_len == 0 &&
		    (eor == 0 ||
		     (((o = m->m_next) || (o = tailm)) &&
		      o->m_type == m->m_type))) {
			o = m->m_next;
			m->m_next = free_chain;
			free_chain = m;
			m = o;
			continue;
		}

		/* See if we can coalesce with preceding mbuf. */
		if (tailm && !(tailm->m_flags & M_EOR) && M_WRITABLE(tailm) &&
		    m->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */
		    m->m_len <= M_TRAILINGSPACE(tailm) &&
		    tailm->m_type == m->m_type) {
			u_long mbcnt_sz;

			bcopy(mtod(m, caddr_t),
			      mtod(tailm, caddr_t) + tailm->m_len,
			      (unsigned)m->m_len);
			tailm->m_len += m->m_len;

			sb->sb_cc += m->m_len;		/* update sb counter */

			/*
			 * Fix the wrongly updated mbcnt_prealloc
			 */
			mbcnt_sz = MSIZE;
			if (m->m_flags & M_EXT)
				mbcnt_sz += m->m_ext.ext_size;
			atomic_subtract_long(&sb->sb_mbcnt_prealloc, mbcnt_sz);

			o = m->m_next;
			m->m_next = free_chain;
			free_chain = m;
			m = o;
			continue;
		}

		/* Insert whole mbuf. */
		if (tailm == NULL) {
			KASSERT(sb->sb_mb == NULL,
				("sbcompress: sb_mb not NULL"));
			sb->sb_mb = m;		/* only mbuf in sockbuf */
			sb->sb_lastrecord = m;	/* new last record */
		} else {
			tailm->m_next = m;	/* tack m on following tailm */
		}
		sb->sb_lastmbuf = m;	/* update last mbuf hint */

		tailm = m;	/* just inserted mbuf becomes the new tail */
		m = m->m_next;		/* advance to next mbuf */
		tailm->m_next = NULL;	/* split inserted mbuf off from chain */

		/* update sb counters for just added mbuf */
		sballoc(sb, tailm);

		/* clear EOR on intermediate mbufs */
		tailm->m_flags &= ~M_EOR;
	}

	/*
	 * Propogate EOR to the last mbuf
	 */
	if (eor) {
		if (tailm)
			tailm->m_flags |= eor;
		else
			kprintf("semi-panic: sbcompress");
	}

	/*
	 * Clean up any defered frees.
	 */
	while (free_chain)
		free_chain = m_free(free_chain);

	sbcheck(sb);
}