Subject: Re: m_pulldown()
To: Matt Thomas <matt@3am-software.com>
From: None <itojun@iijlab.net>
List: tech-net
Date: 12/03/1999 13:16:14
>The function I'm proposing is:
>void *m_extract(struct mbuf *m, size_t offset, size_t len, size_t alignment, void *buf);
>
>which returns a pointer to a region of the mbuf iff the data desired is contiguous and
>aligned properly otherwise the supplied parameter buf is returned. alignment is minimum
>alignment required for the buffer.
>
>The routine should panic if offset + len > the length of the mbuf.
I think m_pulldown() is much simpler on variable-length headers
(IPv6 uses many of them):
- for m_extract how much buffer do we need to pre-allocate is not known.
m_pulldown() does not have the problem (uses mbuf).
- m_extract makes copy twice for same region, for variable length
header. (you can't avoid it as the copy/non-copy is hidden
in the funtion)
m_pulldown() can avoid copy as long as "len" fits into MLEN.
- we are not certain if copy is performed or not, so we are not sure
if we can overwrite it or not (the answer is to use m_copydata when
we need overwrite, but i imagine people will misinterpret it)
How did you code variable-length header case?
itojun
--- m_extract
struct foohdr *f;
f = m_extract(m, off, sizeof(struct foohdr), 8, buf));
if (f->len > sizeof(buf))
panic("bang");
#if 1
/* makes copy twice on the same region */
m_extract(m, off, f->len, 8, buf);
#endif
/*
* you can't do it as you are uncertain if the first m_extract
* made a copy of not, and if second m_extract makes a copy or not.
*/
m_extract(m, off + sizeof(struct foohdr),
f->len - sizeof(struct foohdr), 8, buf + sizeof(struct foohdr));
#endif
--- if you prefer NOT to split header... (actually we got a macro for this)
struct mbuf *n;
struct foohdr *f;
int newoff = 0;
n = m_pulldown(m, off, sizeof(struct foohdr), &newoff);
f = (struct foohdr *)(mtod(n, caddr_t) + newoff);
/*
* this one never copy the same region twice, as long as
* f->len - sizeof(struct foohdr) < M_TRAILINGSPACE(n)
*/
n = m_pulldown(m, off, f->len, &newoff);
f = (struct foohdr *)(mtod(n, caddr_t) + newoff);
--- or, if you prefer to split the header....
struct mbuf *n;
struct foohdr *f;
n = m_pulldown(m, off, sizeof(struct foohdr), NULL);
f = mtod(n, struct foohdr *);
n = m_pulldown(m, off, f->len, NULL);
f = mtod(n, struct foohdr *);