#ifndef _SYS_MBUF_H_
#define _SYS_MBUF_H_
#if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
#ifndef _SYS_TYPES_H_
#include <sys/types.h>
#endif
#ifndef _SYS_PARAM_H_
#include <sys/param.h>
#endif
#ifndef _SYS_QUEUE_H_
#include <sys/queue.h>
#endif
#ifndef _NET_NETISR_H_
#include <net/netisr.h>
#endif
#ifndef _NET_ETHERNET_H_
#include <net/ethernet.h>
#endif
#define MLEN (MSIZE - sizeof(struct m_hdr))
#define MHLEN (MLEN - sizeof(struct pkthdr))
#define MINCLSIZE (MHLEN + 1)
#define M_MAXCOMPRESS (MHLEN / 2)
#define mtod(m, t) ((t)((m)->m_data))
#define mtodoff(m, t, off) ((t)((m)->m_data + (off)))
struct m_hdr {
struct mbuf *mh_next;
union {
struct mbuf *mh_nextpkt;
STAILQ_ENTRY(mbuf) mh_stailqpkt;
};
caddr_t mh_data;
int mh_len;
int mh_flags;
short mh_type;
short mh_pad;
#ifdef MBUF_DEBUG
const char *mh_lastfunc;
#endif
union {
struct netmsg_packet mhm_pkt;
struct netmsg_pru_send mhm_snd;
struct netmsg_inarp mhm_arp;
struct netmsg_ctlinput mhm_ctl;
struct netmsg_genpkt mhm_gen;
struct netmsg_forward mhm_fwd;
} mh_msgu;
};
#define mh_netmsg mh_msgu.mhm_pkt
#define mh_sndmsg mh_msgu.mhm_snd
#define mh_arpmsg mh_msgu.mhm_arp
#define mh_ctlmsg mh_msgu.mhm_ctl
#define mh_genmsg mh_msgu.mhm_gen
#define mh_fwdmsg mh_msgu.mhm_fwd
struct pkthdr_pf {
void *hdr;
void *statekey;
u_int rtableid;
uint32_t qid;
uint16_t tag;
uint8_t flags;
uint8_t routed;
uint32_t state_hash;
uint8_t ecn_af;
uint8_t unused01;
uint8_t unused02;
uint8_t unused03;
};
#define PF_TAG_GENERATED 0x01
#define PF_TAG_FRAGCACHE 0x02
#define PF_TAG_TRANSLATE_LOCALHOST 0x04
#define PF_TAG_DIVERTED 0x08
#define PF_TAG_DIVERTED_PACKET 0x10
#define PF_TAG_REROUTE 0x20
struct m_tag {
SLIST_ENTRY(m_tag) m_tag_link;
uint16_t m_tag_id;
uint16_t m_tag_len;
uint32_t m_tag_cookie;
};
SLIST_HEAD(packet_tags, m_tag);
struct pkthdr {
struct ifnet *rcvif;
struct packet_tags tags;
void *header;
int len;
int csum_flags;
int csum_data;
uint16_t csum_iphlen;
uint8_t csum_thlen;
uint8_t csum_lhlen;
uint16_t tso_segsz;
uint16_t ether_vlantag;
uint16_t hash;
uint16_t unused1;
uint32_t unused2;
uint16_t wlan_seqno;
uint8_t ether_br_shost[ETHER_ADDR_LEN];
uint32_t fw_flags;
struct pkthdr_pf pf;
};
struct m_ext {
caddr_t ext_buf;
void (*ext_free)(void *);
u_int ext_size;
void (*ext_ref)(void *);
void *ext_arg;
};
struct mbuf {
struct m_hdr m_hdr;
union {
struct {
struct pkthdr MH_pkthdr;
union {
struct m_ext MH_ext;
char MH_databuf[MHLEN];
} MH_dat;
} MH;
char M_databuf[MLEN];
} M_dat;
};
#define m_next m_hdr.mh_next
#define m_len m_hdr.mh_len
#define m_data m_hdr.mh_data
#define m_type m_hdr.mh_type
#define m_flags m_hdr.mh_flags
#define m_nextpkt m_hdr.mh_nextpkt
#define m_stailqpkt m_hdr.mh_stailqpkt
#define m_pkthdr M_dat.MH.MH_pkthdr
#define m_ext M_dat.MH.MH_dat.MH_ext
#define m_pktdat M_dat.MH.MH_dat.MH_databuf
#define m_dat M_dat.M_databuf
#define m_act m_nextpkt
#define M_EXT 0x0001
#define M_PKTHDR 0x0002
#define M_EOR 0x0004
#define M_PROTO1 0x0008
#define M_PROTO2 0x0010
#define M_PROTO3 0x0020
#define M_PROTO4 0x0040
#define M_PROTO5 0x0080
#define M_BCAST 0x0100
#define M_MCAST 0x0200
#define M_FRAG 0x0400
#define M_FIRSTFRAG 0x0800
#define M_LASTFRAG 0x1000
#define M_CLCACHE 0x2000
#define M_EXT_CLUSTER 0x4000
#define M_PHCACHE 0x8000
#define M_UNUSED16 0x10000
#define M_VLANTAG 0x20000
#define M_MPLSLABELED 0x40000
#define M_LENCHECKED 0x80000
#define M_HASH 0x100000
#define M_PROTO6 0x200000
#define M_PROTO7 0x400000
#define M_PROTO8 0x800000
#define M_CKHASH 0x1000000
#define M_PRIO 0x2000000
#define M_SOLOCKED 0x4000000
#define M_PROTOFLAGS (M_PROTO1|M_PROTO2|M_PROTO3|M_PROTO4|M_PROTO5 | \
M_PROTO6|M_PROTO7|M_PROTO8)
#define M_COPYFLAGS (M_PKTHDR|M_EOR|M_PROTOFLAGS | \
M_BCAST|M_MCAST|M_FRAG|M_FIRSTFRAG|M_LASTFRAG | \
M_VLANTAG|M_MPLSLABELED | \
M_LENCHECKED|M_HASH|M_CKHASH|M_PRIO)
#define CSUM_IP 0x0001
#define CSUM_TCP 0x0002
#define CSUM_UDP 0x0004
#define CSUM_IP_FRAGS 0x0008
#define CSUM_FRAGMENT 0x0010
#define CSUM_IP_CHECKED 0x0100
#define CSUM_IP_VALID 0x0200
#define CSUM_DATA_VALID 0x0400
#define CSUM_PSEUDO_HDR 0x0800
#define CSUM_FRAG_NOT_CHECKED 0x1000
#define CSUM_TSO 0x2000
#define CSUM_DELAY_DATA (CSUM_TCP | CSUM_UDP)
#define CSUM_DELAY_IP (CSUM_IP)
#define FW_MBUF_GENERATED 0x00000001
#define PF_MBUF_STRUCTURE 0x00000002
#define PF_MBUF_ROUTED 0x00000004
#define PF_MBUF_TAGGED 0x00000008
#define IPFW_MBUF_CONTINUE 0x00000010
#define XX_MBUF_UNUSED20 0x00000020
#define IPFORWARD_MBUF_TAGGED 0x00000040
#define DUMMYNET_MBUF_TAGGED 0x00000080
#define BRIDGE_MBUF_TAGGED 0x00000100
#define FW_MBUF_REDISPATCH 0x00000200
#define FW_MBUF_PRIVATE1 0x00000400
#define FW_MBUF_PRIVATE2 0x00000800
#define IPFW_MBUF_GENERATED FW_MBUF_GENERATED
#define MT_FREE 0
#define MT_DATA 1
#define MT_HEADER 2
#define MT_SONAME 3
#define MT_CONTROL 5
#define MT_OOBDATA 6
#define MT_NTYPES 7
struct mbstat {
u_long m_mbufs;
u_long m_clusters;
u_long m_jclusters;
u_long m_clfree;
u_long m_drops;
u_long m_wait;
u_long m_drain;
u_long m_mcfail;
u_long m_mpfail;
u_long m_msize;
u_long m_mclbytes;
u_long m_mjumpagesize;
u_long m_minclsize;
u_long m_mlen;
u_long m_mhlen;
u_long m_pad;
};
#define MB_OCFLAG(how) ((how) & M_WAITOK ? M_WAITOK : M_NOWAIT)
#define MGETHDR_C 1
#define MGET_C 2
#define MGET(m, how, type) do { \
(m) = m_get((how), (type)); \
} while (0)
#define MGETHDR(m, how, type) do { \
(m) = m_gethdr((how), (type)); \
} while (0)
#define MCLGET(m, how) do { \
m_mclget((m), (how)); \
} while (0)
#define M_MOVE_PKTHDR(_to, _from) m_move_pkthdr((_to), (_from))
#define M_ALIGN(m, len) do { \
(m)->m_data += rounddown2(MLEN - (len), sizeof(long)); \
} while (0)
#define MH_ALIGN(m, len) do { \
(m)->m_data += rounddown2(MHLEN - (len), sizeof(long)); \
} while (0)
#define M_EXT_WRITABLE(m) (m_sharecount(m) == 1)
#define M_WRITABLE(m) (!((m)->m_flags & M_EXT) || M_EXT_WRITABLE(m))
#define M_ASSERTPKTHDR(m) \
KASSERT(m != NULL && m->m_flags & M_PKTHDR, \
("%s: invalid mbuf or no mbuf packet header!", __func__))
#define M_LEADINGSPACE(m) \
((m)->m_flags & M_EXT ? \
(M_EXT_WRITABLE(m) ? (m)->m_data - (m)->m_ext.ext_buf : 0): \
(m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat : \
(m)->m_data - (m)->m_dat)
#define M_TRAILINGSPACE(m) \
((m)->m_flags & M_EXT ? \
(M_WRITABLE(m) ? (m)->m_ext.ext_buf + (m)->m_ext.ext_size \
- ((m)->m_data + (m)->m_len) : 0) : \
&(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len))
#define M_PREPEND(m, plen, how) do { \
struct mbuf **_mmp = &(m); \
struct mbuf *_mm = *_mmp; \
int _mplen = (plen); \
int __mhow = (how); \
\
if (M_LEADINGSPACE(_mm) >= _mplen) { \
_mm->m_data -= _mplen; \
_mm->m_len += _mplen; \
} else \
_mm = m_prepend(_mm, _mplen, __mhow); \
if (_mm != NULL && (_mm->m_flags & M_PKTHDR)) \
_mm->m_pkthdr.len += _mplen; \
*_mmp = _mm; \
} while (0)
#define M_COPYALL 1000000000
#define m_copy(m, o, l) m_copym((m), (o), (l), M_NOWAIT)
#ifdef _KERNEL
extern u_int m_clalloc_wid;
extern u_int m_mballoc_wid;
extern int max_linkhdr;
extern int max_protohdr;
extern int max_hdr;
extern int max_datalen;
extern int nmbclusters;
extern int nmbufs;
struct uio;
void mcl_inclimit(int);
void mjcl_inclimit(int);
void mb_inclimit(int);
void m_adj(struct mbuf *, int);
void m_align(struct mbuf *, int);
int m_apply(struct mbuf *, int, int,
int (*)(void *, void *, u_int), void *);
int m_append(struct mbuf *, int, const void *);
void m_cat(struct mbuf *, struct mbuf *);
u_int m_countm(struct mbuf *m, struct mbuf **lastm, u_int *mbcnt);
void m_copyback(struct mbuf *, int, int, const void *);
int m_copyback2(struct mbuf *, int, int, const void *, int);
void m_copydata(const struct mbuf *, int, int, void *);
struct mbuf *m_copym(const struct mbuf *, int, int, int);
struct mbuf *m_copypacket(struct mbuf *, int);
struct mbuf *m_defrag(struct mbuf *, int);
struct mbuf *m_defrag_nofree(struct mbuf *, int);
struct mbuf *m_devget(void *, int, int, struct ifnet *);
struct mbuf *m_dup(struct mbuf *, int);
struct mbuf *m_dup_data(struct mbuf *, int);
int m_dup_pkthdr(struct mbuf *, const struct mbuf *, int);
void m_extadd(struct mbuf *, void *, u_int, void (*)(void *),
void (*)(void *), void *);
#ifdef MBUF_DEBUG
struct mbuf *_m_free(struct mbuf *, const char *name);
void _m_freem(struct mbuf *, const char *name);
#else
struct mbuf *m_free(struct mbuf *);
void m_freem(struct mbuf *);
#endif
struct mbuf *m_get(int, int);
struct mbuf *m_getc(int len, int how, int type);
struct mbuf *m_getcl(int how, short type, int flags);
struct mbuf *m_getjcl(int how, short type, int flags, size_t size);
struct mbuf *m_getclr(int, int);
struct mbuf *m_gethdr(int, int);
struct mbuf *m_getm(struct mbuf *, int, int, int);
struct mbuf *m_getptr(struct mbuf *, int, int *);
struct mbuf *m_last(struct mbuf *m);
u_int m_lengthm(struct mbuf *m, struct mbuf **lastm);
void m_move_pkthdr(struct mbuf *, struct mbuf *);
struct mbuf *m_prepend(struct mbuf *, int, int);
void m_print(const struct mbuf *m);
struct mbuf *m_pulldown(struct mbuf *, int, int, int *);
struct mbuf *m_pullup(struct mbuf *, int);
struct mbuf *m_split(struct mbuf *, int, int);
struct mbuf *m_uiomove(struct uio *);
struct mbuf *m_unshare(struct mbuf *, int);
void m_mclget(struct mbuf *m, int how);
int m_sharecount(struct mbuf *m);
void m_chtype(struct mbuf *m, int type);
int m_devpad(struct mbuf *m, int padto);
#ifdef MBUF_DEBUG
void mbuftrackid(struct mbuf *, int);
#define m_free(m) _m_free(m, __func__)
#define m_freem(m) _m_freem(m, __func__)
#else
#define mbuftrackid(m, id)
#endif
static __inline void
m_sethash(struct mbuf *m, uint16_t hash)
{
m->m_flags |= M_HASH;
m->m_pkthdr.hash = hash;
}
static __inline struct mbuf *
m_getl(int len, int how, int type, int flags, int *psize)
{
struct mbuf *m;
int size;
if (len >= MINCLSIZE) {
m = m_getcl(how, type, flags);
size = MCLBYTES;
} else if (flags & M_PKTHDR) {
m = m_gethdr(how, type);
size = MHLEN;
} else {
m = m_get(how, type);
size = MLEN;
}
if (psize != NULL)
*psize = size;
return (m);
}
static __inline struct mbuf *
m_getlj(int len, int how, int type, int flags, int *psize)
{
if (len > MCLBYTES) {
struct mbuf *m;
m = m_getjcl(how, type, flags, MJUMPAGESIZE);
if (psize != NULL)
*psize = MJUMPAGESIZE;
return m;
}
return m_getl(len, how, type, flags, psize);
}
static __inline struct mbuf *
m_getb(int len, int how, int type, int flags)
{
struct mbuf *m;
int mbufsize = (flags & M_PKTHDR) ? MHLEN : MLEN;
if (len > mbufsize)
m = m_getcl(how, type, flags);
else if (flags & M_PKTHDR)
m = m_gethdr(how, type);
else
m = m_get(how, type);
return (m);
}
#define PACKET_TAG_NONE 0
#define PACKET_TAG_ENCAP 6
#define PACKET_TAG_IPV6_INPUT 8
#define PACKET_TAG_IPFW_DIVERT 9
#define PACKET_TAG_DUMMYNET 15
#define PACKET_TAG_IPFORWARD 18
#define PACKET_TAG_IPSRCRT 27
#define PACKET_TAG_CARP 28
#define PACKET_TAG_PF 29
#define PACKET_TAG_PF_DIVERT 0x0200
struct m_tag *m_tag_alloc(uint32_t, int, int, int);
void m_tag_free(struct m_tag *);
void m_tag_prepend(struct mbuf *, struct m_tag *);
void m_tag_unlink(struct mbuf *, struct m_tag *);
void m_tag_delete(struct mbuf *, struct m_tag *);
void m_tag_delete_chain(struct mbuf *);
struct m_tag *m_tag_locate(struct mbuf *, uint32_t, int, struct m_tag *);
struct m_tag *m_tag_copy(struct m_tag *, int);
int m_tag_copy_chain(struct mbuf *, const struct mbuf *, int);
void m_tag_init(struct mbuf *);
struct m_tag *m_tag_first(struct mbuf *);
struct m_tag *m_tag_next(struct mbuf *, struct m_tag *);
#define MTAG_ABI_COMPAT 0
static __inline void *
m_tag_data(struct m_tag *tag)
{
return ((void *)(tag + 1));
}
static __inline struct m_tag *
m_tag_get(int type, int length, int mflags)
{
return m_tag_alloc(MTAG_ABI_COMPAT, type, length, mflags);
}
static __inline struct m_tag *
m_tag_find(struct mbuf *m, int type, struct m_tag *start)
{
return m_tag_locate(m, MTAG_ABI_COMPAT, type, start);
}
struct mbufq {
STAILQ_HEAD(, mbuf) mq_head;
int mq_len;
int mq_maxlen;
};
static inline void
mbufq_init(struct mbufq *mq, int maxlen)
{
STAILQ_INIT(&mq->mq_head);
mq->mq_maxlen = maxlen;
mq->mq_len = 0;
}
static inline struct mbuf *
mbufq_flush(struct mbufq *mq)
{
struct mbuf *m;
m = STAILQ_FIRST(&mq->mq_head);
STAILQ_INIT(&mq->mq_head);
mq->mq_len = 0;
return (m);
}
static inline void
mbufq_drain(struct mbufq *mq)
{
struct mbuf *m, *n;
n = mbufq_flush(mq);
while ((m = n) != NULL) {
n = STAILQ_NEXT(m, m_stailqpkt);
m_freem(m);
}
}
static inline struct mbuf *
mbufq_first(const struct mbufq *mq)
{
return (STAILQ_FIRST(&mq->mq_head));
}
static inline struct mbuf *
mbufq_last(const struct mbufq *mq)
{
return (STAILQ_LAST(&mq->mq_head, mbuf, m_stailqpkt));
}
static inline int
mbufq_full(const struct mbufq *mq)
{
return (mq->mq_len >= mq->mq_maxlen);
}
static inline int
mbufq_len(const struct mbufq *mq)
{
return (mq->mq_len);
}
static inline int
mbufq_enqueue(struct mbufq *mq, struct mbuf *m)
{
if (mbufq_full(mq))
return (ENOBUFS);
STAILQ_INSERT_TAIL(&mq->mq_head, m, m_stailqpkt);
mq->mq_len++;
return (0);
}
static inline struct mbuf *
mbufq_dequeue(struct mbufq *mq)
{
struct mbuf *m;
m = STAILQ_FIRST(&mq->mq_head);
if (m) {
STAILQ_REMOVE_HEAD(&mq->mq_head, m_stailqpkt);
m->m_nextpkt = NULL;
mq->mq_len--;
}
return (m);
}
static inline void
mbufq_prepend(struct mbufq *mq, struct mbuf *m)
{
STAILQ_INSERT_HEAD(&mq->mq_head, m, m_stailqpkt);
mq->mq_len++;
}
#endif
#endif
#endif