/*-
* Copyright (c) 2009-2020 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This material is based upon work partially supported by The
* NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* NPF network buffer management interface.
*
* Network buffer in NetBSD is mbuf. Internal mbuf structures are
* abstracted within this source.
*/
void
nbuf_unset_flag(nbuf_t *nbuf, int flag)
{
nbuf->nb_flags &= ~flag;
}
/*
* nbuf_advance: advance in nbuf or chain by specified amount of bytes and,
* if requested, ensure that the area *after* advance is contiguous.
*
* => Returns new pointer to data in nbuf or NULL if offset is invalid.
* => Current nbuf and the offset is stored in the nbuf metadata.
*/
void *
nbuf_advance(nbuf_t *nbuf, size_t len, size_t ensure)
{
struct mbuf *m = nbuf->nb_mbuf;
unsigned off, wmark;
uint8_t *d;
/* Offset with amount to advance. */
off = (uintptr_t)nbuf->nb_nptr - mtod(m, uintptr_t) + len;
wmark = m_buflen(m);
/* Find the mbuf according to offset. */
while (__predict_false(wmark <= off)) {
m = m_next_ptr(m);
if (__predict_false(m == NULL)) {
/*
* If end of the chain, then the offset is
* higher than packet length.
*/
return NULL;
}
wmark += m_buflen(m);
}
KASSERT(off < m_length(nbuf->nb_mbuf0));
/* Offset in mbuf data. */
d = mtod(m, uint8_t *);
KASSERT(off >= (wmark - m_buflen(m)));
d += (off - (wmark - m_buflen(m)));
nbuf->nb_mbuf = m;
nbuf->nb_nptr = d;
if (ensure) {
/* Ensure contiguousness (may change nbuf chain). */
d = nbuf_ensure_contig(nbuf, ensure);
}
return d;
}
/*
* nbuf_ensure_contig: check whether the specified length from the current
* point in the nbuf is contiguous. If not, rearrange the chain to be so.
*
* => Returns pointer to the data at the current offset in the buffer.
* => Returns NULL on failure and nbuf becomes invalid.
*/
void *
nbuf_ensure_contig(nbuf_t *nbuf, size_t len)
{
const struct mbuf * const n = nbuf->nb_mbuf;
const size_t off = (uintptr_t)nbuf->nb_nptr - mtod(n, uintptr_t);
/* Attempt to round-up to NBUF_ENSURE_ALIGN bytes. */
if ((target = NBUF_ENSURE_ROUNDUP(foff + len)) > plen) {
target = foff + len;
}
/* Rearrange the chain to be contiguous. */
KASSERT(m_flags_p(m, M_PKTHDR));
success = m_ensure_contig(&m, target);
KASSERT(m != NULL);
/* If no change in the chain: return what we have. */
if (m == nbuf->nb_mbuf0 && m_buflen(m) == mlen) {
return success ? nbuf->nb_nptr : NULL;
}
/*
* The mbuf chain was re-arranged. Update the pointers
* accordingly and indicate that the references to the data
* might need a reset.
*/
KASSERT(m_flags_p(m, M_PKTHDR));
nbuf->nb_mbuf0 = m;
nbuf->nb_mbuf = m;
/*
* npf_mbuf_add_tag: associate a tag with the network buffer.
*
* => Returns 0 on success or error number on failure.
*/
int
npf_mbuf_add_tag(nbuf_t *nbuf, struct mbuf *m, uint32_t val)
{
#ifdef _KERNEL
struct m_tag *mt;
uint32_t *dat;
/*
* nbuf_add_tag: associate a tag with the network buffer.
*
* => Returns 0 on success or error number on failure.
*/
int
nbuf_add_tag(nbuf_t *nbuf, uint32_t val)
{
struct mbuf *m = nbuf->nb_mbuf0;
return npf_mbuf_add_tag(nbuf, m, val);
}
/*
* nbuf_find_tag: find a tag associated with a network buffer.
*
* => Returns 0 on success or error number on failure.
*/
int
nbuf_find_tag(nbuf_t *nbuf, uint32_t *val)
{
struct mbuf *m = nbuf->nb_mbuf0;
#ifdef _KERNEL
struct m_tag *mt;