uipc_mbuf.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,167 行 · 第 1/2 页

C
1,167
字号
		}		MGET(n, wait, m->m_type);		*np = n;		if (n == 0)			goto nospace;		if (copyhdr) {			M_COPY_PKTHDR(n, m);			if (len == M_COPYALL)				n->m_pkthdr.len -= off0;			else				n->m_pkthdr.len = len;			copyhdr = 0;		}		n->m_len = min(len, m->m_len - off);		if (m->m_flags & M_EXT) {			n->m_data = m->m_data + off;			if(!m->m_ext.ext_ref)				mclrefcnt[mtocl(m->m_ext.ext_buf)]++;			else				(*(m->m_ext.ext_ref))(m->m_ext.ext_buf,							m->m_ext.ext_size);			n->m_ext = m->m_ext;			n->m_flags |= M_EXT;		} else			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),			    (unsigned)n->m_len);		if (len != M_COPYALL)			len -= n->m_len;		off = 0;		m = m->m_next;		np = &n->m_next;	}	if (top == 0)		MCFail++;	return (top);nospace:	m_freem(top);	MCFail++;	return (0);}/* * Copy an entire packet, including header (which must be present). * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'. * Note that the copy is read-only, because clusters are not copied, * only their reference counts are incremented. */struct mbuf *m_copypacket(m, how)	struct mbuf *m;	int how;{	struct mbuf *top, *n, *o;	MGET(n, how, m->m_type);	top = n;	if (!n)		goto nospace;	M_COPY_PKTHDR(n, m);	n->m_len = m->m_len;	if (m->m_flags & M_EXT) {		n->m_data = m->m_data;		if(!m->m_ext.ext_ref)			mclrefcnt[mtocl(m->m_ext.ext_buf)]++;		else			(*(m->m_ext.ext_ref))(m->m_ext.ext_buf,						m->m_ext.ext_size);		n->m_ext = m->m_ext;		n->m_flags |= M_EXT;	} else {		bcopy(mtod(m, char *), mtod(n, char *), n->m_len);	}	m = m->m_next;	while (m) {		MGET(o, how, m->m_type);		if (!o)			goto nospace;		n->m_next = o;		n = n->m_next;		n->m_len = m->m_len;		if (m->m_flags & M_EXT) {			n->m_data = m->m_data;			if(!m->m_ext.ext_ref)				mclrefcnt[mtocl(m->m_ext.ext_buf)]++;			else				(*(m->m_ext.ext_ref))(m->m_ext.ext_buf,							m->m_ext.ext_size);			n->m_ext = m->m_ext;			n->m_flags |= M_EXT;		} else {			bcopy(mtod(m, char *), mtod(n, char *), n->m_len);		}		m = m->m_next;	}	return top;nospace:	m_freem(top);	MCFail++;	return 0;}/* * Copy data from an mbuf chain starting "off" bytes from the beginning, * continuing for "len" bytes, into the indicated buffer. */voidm_copydata(m, off, len, cp)	register struct mbuf *m;	register int off;	register int len;	caddr_t cp;{	register unsigned count;	while (off > 0) {		if (off < m->m_len)			break;		off -= m->m_len;		m = m->m_next;	}	while (len > 0) {		count = min(m->m_len - off, len);		bcopy(mtod(m, caddr_t) + off, cp, count);		len -= count;		cp += count;		off = 0;		m = m->m_next;	}}/* * Copy a packet header mbuf chain into a completely new chain, including * copying any mbuf clusters.  Use this instead of m_copypacket() when * you need a writable copy of an mbuf chain. */struct mbuf *m_dup(m, how)	struct mbuf *m;	int how;{	struct mbuf **p, *top = NULL;	int remain, moff, nsize;	/* Sanity check */	if (m == NULL)		return (0);	/* While there's more data, get a new mbuf, tack it on, and fill it */	remain = m->m_pkthdr.len;	moff = 0;	p = &top;	while (remain > 0 || top == NULL) {	/* allow m->m_pkthdr.len == 0 */		struct mbuf *n;		/* Get the next new mbuf */		MGET(n, how, m->m_type);		if (n == NULL)			goto nospace;		if (top == NULL) {		/* first one, must be PKTHDR */			M_COPY_PKTHDR(n, m);			nsize = MHLEN;		} else				/* not the first one */			nsize = MLEN;		if (remain >= MINCLSIZE) {			MCLGET(n, how);			if ((n->m_flags & M_EXT) == 0) {				(void)m_free(n);				goto nospace;			}			nsize = MCLBYTES;		}		n->m_len = 0;		/* Link it into the new chain */		*p = n;		p = &n->m_next;		/* Copy data from original mbuf(s) into new mbuf */		while (n->m_len < nsize && m != NULL) {			int chunk = min(nsize - n->m_len, m->m_len - moff);			bcopy(m->m_data + moff, n->m_data + n->m_len, chunk);			moff += chunk;			n->m_len += chunk;			remain -= chunk;			if (moff == m->m_len) {				m = m->m_next;				moff = 0;			}		}	}	return (top);nospace:	m_freem(top);	MCFail++;	return (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. */voidm_cat(m, n)	register struct mbuf *m, *n;{	while (m->m_next)		m = m->m_next;	while (n) {		if (m->m_flags & M_EXT ||		    m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {			/* 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);	}}voidm_adj(mp, req_len)	struct mbuf *mp;	int req_len;{	register int len = req_len;	register struct mbuf *m;	register int count;	if ((m = mp) == NULL)		return;	if (len >= 0) {		/*		 * Trim from head.		 */		while (m != NULL && len > 0) {			if (m->m_len <= len) {				len -= m->m_len;				m->m_len = 0;				m = m->m_next;			} else {				m->m_len -= len;				m->m_data += len;				len = 0;			}		}		m = mp;		if (mp->m_flags & M_PKTHDR)			m->m_pkthdr.len -= (req_len - len);	} else {		/*		 * Trim from tail.  Scan the mbuf chain,		 * calculating its length and finding the last mbuf.		 * If the adjustment only affects this mbuf, then just		 * adjust and return.  Otherwise, rescan and truncate		 * after the remaining size.		 */		len = -len;		count = 0;		for (;;) {			count += m->m_len;			if (m->m_next == (struct mbuf *)0)				break;			m = m->m_next;		}		if (m->m_len >= len) {			m->m_len -= len;			if (mp->m_flags & M_PKTHDR)				mp->m_pkthdr.len -= len;			return;		}		count -= len;		if (count < 0)			count = 0;		/*		 * Correct length for chain is "count".		 * Find the mbuf with last data, adjust its length,		 * and toss data from remaining mbufs on chain.		 */		m = mp;		if (m->m_flags & M_PKTHDR)			m->m_pkthdr.len = count;		for (; m; m = m->m_next) {			if (m->m_len >= count) {				m->m_len = count;				break;			}			count -= m->m_len;		}		while (m->m_next)			(m = m->m_next) ->m_len = 0;	}}/* * Rearange an mbuf chain so that len bytes are contiguous * and in the data area of an mbuf (so that mtod and dtom * will work for a structure of size len).  Returns the resulting * mbuf chain on success, frees it and returns null on failure. * If there is room, it will add up to max_protohdr-len extra bytes to the * contiguous region in an attempt to avoid being called next time. */#define MPFail (mbstat.m_mpfail)struct mbuf *m_pullup(n, len)	register struct mbuf *n;	int len;{	register struct mbuf *m;	register int count;	int space;	/*	 * If first mbuf has no cluster, and has room for len bytes	 * without shifting current data, pullup into it,	 * otherwise allocate a new mbuf to prepend to the chain.	 */	if ((n->m_flags & M_EXT) == 0 &&	    n->m_data + len < &n->m_dat[MLEN] && n->m_next) {		if (n->m_len >= len)			return (n);		m = n;		n = n->m_next;		len -= m->m_len;	} else {		if (len > MHLEN)			goto bad;		MGET(m, M_DONTWAIT, n->m_type);		if (m == 0)			goto bad;		m->m_len = 0;		if (n->m_flags & M_PKTHDR) {			M_COPY_PKTHDR(m, n);			n->m_flags &= ~M_PKTHDR;		}	}	space = &m->m_dat[MLEN] - (m->m_data + m->m_len);	do {		count = min(min(max(len, max_protohdr), space), n->m_len);		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,		  (unsigned)count);		len -= count;		m->m_len += count;		n->m_len -= count;		space -= count;		if (n->m_len)			n->m_data += count;		else			n = m_free(n);	} while (len > 0 && n);	if (len > 0) {		(void) m_free(m);		goto bad;	}	m->m_next = n;	return (m);bad:	m_freem(n);	MPFail++;	return (0);}/* * Partition an mbuf chain in two pieces, returning the tail -- * all but the first len0 bytes.  In case of failure, it returns NULL and * attempts to restore the chain to its original state. */struct mbuf *m_split(m0, len0, wait)	register struct mbuf *m0;	int len0, wait;{	register struct mbuf *m, *n;	unsigned len = len0, remain;	for (m = m0; m && len > m->m_len; m = m->m_next)		len -= m->m_len;	if (m == 0)		return (0);	remain = m->m_len - len;	if (m0->m_flags & M_PKTHDR) {		MGETHDR(n, wait, m0->m_type);		if (n == 0)			return (0);		n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;		n->m_pkthdr.len = m0->m_pkthdr.len - len0;		m0->m_pkthdr.len = len0;		if (m->m_flags & M_EXT)			goto extpacket;		if (remain > MHLEN) {			/* m can't be the lead packet */			MH_ALIGN(n, 0);			n->m_next = m_split(m, len, wait);			if (n->m_next == 0) {				(void) m_free(n);				return (0);			} else				return (n);		} else			MH_ALIGN(n, remain);	} else if (remain == 0) {		n = m->m_next;		m->m_next = 0;		return (n);	} else {		MGET(n, wait, m->m_type);		if (n == 0)			return (0);		M_ALIGN(n, remain);	}extpacket:	if (m->m_flags & M_EXT) {		n->m_flags |= M_EXT;		n->m_ext = m->m_ext;		if(!m->m_ext.ext_ref)			mclrefcnt[mtocl(m->m_ext.ext_buf)]++;		else			(*(m->m_ext.ext_ref))(m->m_ext.ext_buf,						m->m_ext.ext_size);		m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */		n->m_data = m->m_data + len;	} else {		bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);	}	n->m_len = remain;	m->m_len = len;	n->m_next = m->m_next;	m->m_next = 0;	return (n);}/* * Routine to copy from device local memory into mbufs. */struct mbuf *m_devget(buf, totlen, off0, ifp, copy)	char *buf;	int totlen, off0;	struct ifnet *ifp;	void (*copy) __P((char *from, caddr_t to, u_int len));{	register struct mbuf *m;	struct mbuf *top = 0, **mp = &top;	register int off = off0, len;	register char *cp;	char *epkt;	cp = buf;	epkt = cp + totlen;	if (off) {		cp += off + 2 * sizeof(u_short);		totlen -= 2 * sizeof(u_short);	}	MGETHDR(m, M_DONTWAIT, MT_DATA);	if (m == 0)		return (0);	m->m_pkthdr.rcvif = ifp;	m->m_pkthdr.len = totlen;	m->m_len = MHLEN;	while (totlen > 0) {		if (top) {			MGET(m, M_DONTWAIT, MT_DATA);			if (m == 0) {				m_freem(top);				return (0);			}			m->m_len = MLEN;		}		len = min(totlen, epkt - cp);		if (len >= MINCLSIZE) {			MCLGET(m, M_DONTWAIT);			if (m->m_flags & M_EXT)				m->m_len = len = min(len, MCLBYTES);			else				len = m->m_len;		} else {			/*			 * Place initial small packet/header at end of mbuf.			 */			if (len < m->m_len) {				if (top == 0 && len + max_linkhdr <= m->m_len)					m->m_data += max_linkhdr;				m->m_len = len;			} else				len = m->m_len;		}		if (copy)			copy(cp, mtod(m, caddr_t), (unsigned)len);		else			bcopy(cp, mtod(m, caddr_t), (unsigned)len);		cp += len;		*mp = m;		mp = &m->m_next;		totlen -= len;		if (cp == epkt)			cp = buf;	}	return (top);}/* * Copy data from a buffer back into the indicated mbuf chain, * starting "off" bytes from the beginning, extending the mbuf * chain if necessary. */voidm_copyback(m0, off, len, cp)	struct	mbuf *m0;	register int off;	register int len;	caddr_t cp;{	register int mlen;	register struct mbuf *m = m0, *n;	int totlen = 0;	if (m0 == 0)		return;	while (off > (mlen = m->m_len)) {		off -= mlen;		totlen += mlen;		if (m->m_next == 0) {			n = m_getclr(M_DONTWAIT, m->m_type);			if (n == 0)				goto out;			n->m_len = min(MLEN, len + off);			m->m_next = n;		}		m = m->m_next;	}	while (len > 0) {		mlen = min (m->m_len - off, len);		bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);		cp += mlen;		len -= mlen;		mlen += off;		off = 0;		totlen += mlen;		if (len == 0)			break;		if (m->m_next == 0) {			n = m_get(M_DONTWAIT, m->m_type);			if (n == 0)				break;			n->m_len = min(MLEN, len);			m->m_next = n;		}		m = m->m_next;	}out:	if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))		m->m_pkthdr.len = totlen;}#ifndef __ECOSvoidm_print(const struct mbuf *m){	int len;	const struct mbuf *m2;	len = m->m_pkthdr.len;	m2 = m;	while (len) {		printf("%p %*D\n", m2, m2->m_len, (u_char *)m2->m_data, "-");		len -= m2->m_len;		m2 = m2->m_next;	}	return;}#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?