mirror of
https://github.com/lgcosta/pf-linux-port.git
synced 2026-11-13 03:38:04 -03:00
M1: compat layer + pf.ko skeleton builds against Linux 7.3.4
- pfk.h: BSD types/ioctl encoding (OpenBSD bit layout), locks (NET_LOCK=rwsem), pools, timeouts, mbuf shim over sk_buff, ifnet registry, toeplitz/siphash - pfk_mod/pfk_hooks: misc /dev/pf (0600), IPv4 netfilter hook skeleton, DIOCGETSTATUS answered (M1 skeleton; engine ioctls land with pf_ioctl.c) - vendorize/stage-port scripts: deterministic upstream staging with seds (struct renames, IFF_*->PFIFF_*, sa_len drops) logged to docs/porting-notes - fixes: modules_prepare+Module.symvers for out-of-tree builds
This commit is contained in:
1 parent
ba81284bd3
commit
da2e9b679a
87 files changed
+47256
-3
No files matched your search
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* PF-on-Linux mbuf shim implementation (ISC, (c) 2026 PF-on-Linux contributors)
|
||||
* See pfk_mbuf.h for the invariants. All functions run under pfk NET_LOCK
|
||||
* (read side) — never in hardirq context.
|
||||
*/
|
||||
#include <pfk.h>
|
||||
|
||||
static struct kmem_cache *pfk_mbuf_cache;
|
||||
|
||||
struct mbuf *
|
||||
m_get(int how, short type)
|
||||
{
|
||||
return m_gethdr(how, type); /* PF always uses pkthdr packets */
|
||||
}
|
||||
|
||||
struct mbuf *
|
||||
m_gethdr(int how, short type)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct sk_buff *skb;
|
||||
|
||||
m = kmem_cache_zalloc(pfk_mbuf_cache,
|
||||
(how & (M_WAITOK|M_CANFAIL)) == M_WAITOK ? GFP_KERNEL : GFP_ATOMIC);
|
||||
if (!m)
|
||||
return NULL;
|
||||
skb = alloc_skb(256 + NET_SKB_PAD + NET_IP_ALIGN,
|
||||
(how & (M_WAITOK|M_CANFAIL)) == M_WAITOK ? GFP_KERNEL : GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
kmem_cache_free(pfk_mbuf_cache, m);
|
||||
return NULL;
|
||||
}
|
||||
skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
|
||||
m->skb = skb;
|
||||
m->m_data = skb->data;
|
||||
m->m_len = skb->len;
|
||||
m->m_type = type;
|
||||
m->m_flags = M_PKTHDR;
|
||||
m->m_refcnt = 1;
|
||||
m->m_maxsize = skb_tailroom(skb);
|
||||
pfk_m_setpkthdr(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
void
|
||||
pfk_m_setpkthdr(struct mbuf *m)
|
||||
{
|
||||
m->m_flags |= M_PKTHDR;
|
||||
m->m_pkthdr.len = m->m_len;
|
||||
m->m_pkthdr.pf.tag = NULL;
|
||||
m->m_pkthdr.tags = NULL;
|
||||
}
|
||||
|
||||
struct mbuf *
|
||||
m_alloc_skb(struct sk_buff *skb, int how)
|
||||
{
|
||||
struct mbuf *m;
|
||||
|
||||
m = kmem_cache_zalloc(pfk_mbuf_cache,
|
||||
(how & (M_WAITOK|M_CANFAIL)) == M_WAITOK ? GFP_KERNEL : GFP_ATOMIC);
|
||||
if (!m) {
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
m->skb = skb;
|
||||
m->m_data = skb->data;
|
||||
m->m_len = skb->len;
|
||||
m->m_type = MT_HEADER;
|
||||
m->m_refcnt = 1;
|
||||
pfk_m_setpkthdr(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/* reverse map: stash mbuf ptr in skb->cb (documented exclusivity in spec §4.1) */
|
||||
struct pfk_skb_cb {
|
||||
struct mbuf *m;
|
||||
};
|
||||
#define PFK_CB(skb) ((struct pfk_skb_cb *)((skb)->cb))
|
||||
|
||||
struct mbuf *
|
||||
m_dtom(struct sk_buff *skb)
|
||||
{
|
||||
return PFK_CB(skb)->m;
|
||||
}
|
||||
|
||||
struct mbuf *
|
||||
m_devget(char *buf, int totlen, int off, struct pfk_ifnet *ifp,
|
||||
void (*copyin_fc)(caddr_t, int))
|
||||
{
|
||||
struct mbuf *m;
|
||||
|
||||
if (off) {
|
||||
buf += off;
|
||||
totlen -= off;
|
||||
}
|
||||
if (totlen < 0)
|
||||
return NULL;
|
||||
m = m_gethdr(M_NOWAIT, MT_DATA);
|
||||
if (!m)
|
||||
return NULL;
|
||||
if (skb_put(m->skb, totlen) == NULL) {
|
||||
m_freem(m);
|
||||
return NULL;
|
||||
}
|
||||
if (copyin_fc)
|
||||
copyin_fc(mtod(m, caddr_t), totlen);
|
||||
else
|
||||
memcpy(m->skb->data, buf, totlen);
|
||||
pfk_mbuf_refresh(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
int
|
||||
pfk_mbuf_linearize(struct mbuf *m)
|
||||
{
|
||||
if (skb_is_nonlinear(m->skb)) {
|
||||
struct sk_buff *ns;
|
||||
|
||||
ns = skb_copy(m->skb, GFP_ATOMIC);
|
||||
if (!ns)
|
||||
return ENOBUFS;
|
||||
consume_skb(m->skb);
|
||||
m->skb = ns;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
pfk_mbuf_refresh(struct mbuf *m)
|
||||
{
|
||||
m->m_data = m->skb->data;
|
||||
m->m_len = m->skb->len;
|
||||
if (m->m_flags & M_PKTHDR)
|
||||
m->m_pkthdr.len = m->m_len;
|
||||
}
|
||||
|
||||
struct mbuf *
|
||||
m_copym(struct mbuf *m, int off, int len, int wait)
|
||||
{
|
||||
struct mbuf *n;
|
||||
struct sk_buff *ns;
|
||||
|
||||
if (len == 0)
|
||||
len = m->m_len - off;
|
||||
if (off > m->m_len || len > m->m_len - off)
|
||||
return NULL;
|
||||
ns = alloc_skb(len + NET_SKB_PAD + NET_IP_ALIGN,
|
||||
wait == M_WAITOK ? GFP_KERNEL : GFP_ATOMIC);
|
||||
if (!ns)
|
||||
return NULL;
|
||||
skb_reserve(ns, NET_SKB_PAD + NET_IP_ALIGN);
|
||||
if (skb_copy_bits(m->skb, off, skb_put(ns, len), len)) {
|
||||
kfree_skb(ns);
|
||||
return NULL;
|
||||
}
|
||||
n = m_alloc_skb(ns, wait);
|
||||
if (!n)
|
||||
return NULL;
|
||||
if (m->m_flags & M_PKTHDR) {
|
||||
n->m_pkthdr = m->m_pkthdr;
|
||||
n->m_pkthdr.len = len;
|
||||
n->m_pkthdr.tags = NULL;
|
||||
if (m_tag_copy_chain(n, m, wait) != 0) {
|
||||
m_freem(n);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
struct mbuf *
|
||||
m_dup(struct mbuf *m, int wait)
|
||||
{
|
||||
struct mbuf *n = m_copym(m, 0, m->m_len, wait);
|
||||
|
||||
if (n) {
|
||||
struct sk_buff *ns = n->skb;
|
||||
int need = 256 - skb_headroom(ns);
|
||||
|
||||
if (need > 0 &&
|
||||
pskb_expand_head(ns, ALIGN(need, 64), 0,
|
||||
wait == M_WAITOK ? GFP_KERNEL : GFP_ATOMIC)) {
|
||||
m_freem(n);
|
||||
return NULL;
|
||||
}
|
||||
pfk_mbuf_refresh(n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
m_adj(struct mbuf *m, int dlen)
|
||||
{
|
||||
int off = dlen;
|
||||
|
||||
if (off < 0) { /* trim tail */
|
||||
skb_trim(m->skb, m->skb->len + off);
|
||||
} else if (off > 0) {
|
||||
pskb_pull(m->skb, off > m->skb->len ? m->skb->len : off);
|
||||
}
|
||||
pfk_mbuf_refresh(m);
|
||||
}
|
||||
|
||||
void
|
||||
m_trim(struct mbuf *m, int dlen)
|
||||
{
|
||||
skb_trim(m->skb, dlen);
|
||||
pfk_mbuf_refresh(m);
|
||||
}
|
||||
|
||||
int
|
||||
m_cat(struct mbuf *to, struct mbuf *from)
|
||||
{
|
||||
int len = from->m_len;
|
||||
|
||||
if (skb_tailroom(to->skb) < len) {
|
||||
if (pskb_expand_head(to->skb, 0, ALIGN(len, 64), GFP_ATOMIC))
|
||||
return EINVAL;
|
||||
pfk_mbuf_refresh(to);
|
||||
}
|
||||
memcpy(skb_put(to->skb, len), from->m_data, len);
|
||||
pfk_mbuf_refresh(to);
|
||||
m_freem(from);
|
||||
return 0;
|
||||
}
|
||||
|
||||
caddr_t
|
||||
m_copyback(struct mbuf *m, int off, int len, const void *copied)
|
||||
{
|
||||
int grow = off + len - m->m_len;
|
||||
caddr_t p;
|
||||
|
||||
if (off < 0 || len < 0)
|
||||
return mtod(m, caddr_t) + off; /* BSD clamps; PF never does this */
|
||||
if (grow > 0) {
|
||||
if (skb_tailroom(m->skb) < grow) {
|
||||
if (pskb_expand_head(m->skb, 0, ALIGN(grow, 64), GFP_ATOMIC))
|
||||
return NULL;
|
||||
pfk_mbuf_refresh(m);
|
||||
}
|
||||
memset(m->m_data + m->m_len, 0, grow);
|
||||
skb_put(m->skb, grow);
|
||||
pfk_mbuf_refresh(m);
|
||||
}
|
||||
p = m->m_data + off;
|
||||
memcpy(p, copied, len);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
m_copydata(const struct mbuf *m, int off, int len, caddr_t dest)
|
||||
{
|
||||
if (len <= 0)
|
||||
return;
|
||||
if (skb_copy_bits(m->skb, off, dest, len))
|
||||
memcpy(dest, m->m_data + off,
|
||||
len > m->m_len - off ? m->m_len - off : len);
|
||||
}
|
||||
|
||||
caddr_t
|
||||
m_getptr(struct mbuf *m, int loc, int *offp)
|
||||
{
|
||||
*offp = 0;
|
||||
if (loc < 0 || loc >= m->m_len)
|
||||
return NULL;
|
||||
return m->m_data + loc;
|
||||
}
|
||||
|
||||
int
|
||||
m_clump(struct mbuf **m0p, int len, int *mp_off, int *mp_len, caddr_t *doff)
|
||||
{
|
||||
struct mbuf *m = *m0p;
|
||||
|
||||
if (!pskb_may_pull(m->skb, *mp_off + len))
|
||||
return -1;
|
||||
pfk_mbuf_refresh(m);
|
||||
*mp_len = len;
|
||||
*doff = m->m_data + *mp_off;
|
||||
*m0p = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mbuf *
|
||||
m_free(struct mbuf *m)
|
||||
{
|
||||
struct mbuf *n = m->m_next;
|
||||
|
||||
m_tag_delete_chain(m, NULL);
|
||||
if (m->skb) {
|
||||
if (PFK_CB(m->skb)->m == m)
|
||||
PFK_CB(m->skb)->m = NULL;
|
||||
kfree_skb(m->skb);
|
||||
}
|
||||
kmem_cache_free(pfk_mbuf_cache, m);
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
m_freem(struct mbuf *m)
|
||||
{
|
||||
while (m)
|
||||
m = m_free(m);
|
||||
}
|
||||
|
||||
void
|
||||
m_free_ext(struct mbuf *m)
|
||||
{
|
||||
/* PF never attaches external mbuf refs; no-op like upstream ext free */
|
||||
}
|
||||
|
||||
/* ---------------- m_tag ---------------- */
|
||||
struct m_tag *
|
||||
m_tag_alloc(int type, int len, int wait, caddr_t *align_data)
|
||||
{
|
||||
struct m_tag *t;
|
||||
|
||||
t = kmalloc(sizeof(*t) + len + 4,
|
||||
wait == M_WAITOK ? GFP_KERNEL : GFP_ATOMIC);
|
||||
if (!t)
|
||||
return NULL;
|
||||
t->m_tag_next = NULL;
|
||||
t->m_tag_type = type;
|
||||
t->m_tag_len = len;
|
||||
if (align_data)
|
||||
*align_data = PFK_PTR_ALIGN(&t[1]);
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
m_tag_free(struct m_tag *t)
|
||||
{
|
||||
kfree(t);
|
||||
}
|
||||
|
||||
void
|
||||
m_tag_attach(struct mbuf *m, struct m_tag *t)
|
||||
{
|
||||
t->m_tag_next = NULL;
|
||||
if (m->m_pkthdr.tags) {
|
||||
struct m_tag *e = m->m_pkthdr.tags;
|
||||
|
||||
while (e->m_tag_next)
|
||||
e = e->m_tag_next;
|
||||
e->m_tag_next = t;
|
||||
} else
|
||||
m->m_pkthdr.tags = t;
|
||||
}
|
||||
|
||||
void
|
||||
m_tag_prepend(struct mbuf *m, struct m_tag *t)
|
||||
{
|
||||
t->m_tag_next = m->m_pkthdr.tags;
|
||||
m->m_pkthdr.tags = t;
|
||||
}
|
||||
|
||||
void
|
||||
m_tag_prepend_packet(struct mbuf *m, struct m_tag *t)
|
||||
{
|
||||
if (m->m_flags & M_PKTHDR)
|
||||
m_tag_prepend(m, t);
|
||||
else
|
||||
m_tag_free(t);
|
||||
}
|
||||
|
||||
struct m_tag *
|
||||
m_tag_find(struct mbuf *m, int type, struct m_tag *start)
|
||||
{
|
||||
struct m_tag *t;
|
||||
|
||||
if (start == NULL) {
|
||||
if (!(m->m_flags & M_PKTHDR))
|
||||
return NULL;
|
||||
t = m->m_pkthdr.tags;
|
||||
} else
|
||||
t = start->m_tag_next;
|
||||
for (; t; t = t->m_tag_next)
|
||||
if (t->m_tag_type == type)
|
||||
break;
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
m_tag_delete(struct mbuf *m, struct m_tag *t)
|
||||
{
|
||||
struct m_tag **pp = &m->m_pkthdr.tags, *e;
|
||||
|
||||
for (e = m->m_pkthdr.tags; e; e = e->m_tag_next) {
|
||||
if (e == t) {
|
||||
*pp = t->m_tag_next;
|
||||
m_tag_free(t);
|
||||
return;
|
||||
}
|
||||
pp = &e->m_tag_next;
|
||||
}
|
||||
}
|
||||
|
||||
struct m_tag *
|
||||
m_tag_copy(struct m_tag *tag, int how)
|
||||
{
|
||||
struct m_tag *t;
|
||||
caddr_t d;
|
||||
|
||||
t = m_tag_alloc(tag->m_tag_type, tag->m_tag_len, how, &d);
|
||||
if (t)
|
||||
memcpy(d, tag->m_tag_data, tag->m_tag_len);
|
||||
return t;
|
||||
}
|
||||
|
||||
int
|
||||
m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
|
||||
{
|
||||
struct m_tag *t;
|
||||
|
||||
for (t = m_tag_first(from); t; t = m_tag_next(from, t)) {
|
||||
struct m_tag *n = m_tag_copy(t, how);
|
||||
|
||||
if (!n)
|
||||
return ENOBUFS;
|
||||
m_tag_attach(to, n);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
m_tag_delete_chain(struct mbuf *m, struct m_tag *end)
|
||||
{
|
||||
struct m_tag *t, *n;
|
||||
|
||||
if (!(m->m_flags & M_PKTHDR))
|
||||
return;
|
||||
for (t = m->m_pkthdr.tags; t && t != end; t = n) {
|
||||
n = t->m_tag_next;
|
||||
m_tag_free(t);
|
||||
}
|
||||
m->m_pkthdr.tags = end;
|
||||
}
|
||||
|
||||
struct m_tag *
|
||||
m_tag_first(struct mbuf *m)
|
||||
{
|
||||
return (m->m_flags & M_PKTHDR) ? m->m_pkthdr.tags : NULL;
|
||||
}
|
||||
|
||||
struct m_tag *
|
||||
m_tag_next(struct mbuf *m, struct m_tag *t)
|
||||
{
|
||||
return t->m_tag_next;
|
||||
}
|
||||
|
||||
int
|
||||
pfk_mbuf_init(void)
|
||||
{
|
||||
pfk_mbuf_cache = KMEM_CACHE(mbuf, 0);
|
||||
if (!pfk_mbuf_cache)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
pfk_mbuf_exit(void)
|
||||
{
|
||||
kmem_cache_destroy(pfk_mbuf_cache);
|
||||
}
|
||||
Reference in new issue
Block a user