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 *);