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:
lgcosta committed 2026-11-11 12:09:34 -03:00
1 parent ba81284bd3
commit da2e9b679a
87 files changed
+47256 -3

No files matched your search

+83
View File
@@ -0,0 +1,83 @@
/* $OpenBSD: sha2.h,v 1.5 2014/11/16 17:39:09 tedu Exp $ */
/*
* FILE: sha2.h
* AUTHOR: Aaron D. Gifford <me@aarongifford.com>
*
* Copyright (c) 2000-2001, Aaron D. Gifford
* All rights reserved.
*
* 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.
* 3. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 AUTHOR OR CONTRIBUTOR(S) 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.
*
* $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
*/
#ifndef _SHA2_H
#define _SHA2_H
/*** SHA-256/384/512 Various Length Definitions ***********************/
#define SHA256_BLOCK_LENGTH 64
#define SHA256_DIGEST_LENGTH 32
#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1)
#define SHA384_BLOCK_LENGTH 128
#define SHA384_DIGEST_LENGTH 48
#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1)
#define SHA512_BLOCK_LENGTH 128
#define SHA512_DIGEST_LENGTH 64
#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1)
/*** SHA-256/384/512 Context Structure *******************************/
typedef struct _SHA2_CTX {
union {
u_int32_t st32[8];
u_int64_t st64[8];
} state;
u_int64_t bitcount[2];
u_int8_t buffer[SHA512_BLOCK_LENGTH];
} SHA2_CTX;
__BEGIN_DECLS
void SHA256Init(SHA2_CTX *);
void SHA256Update(SHA2_CTX *, const void *, size_t)
__attribute__((__bounded__(__string__,2,3)));
void SHA256Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA2_CTX *)
__attribute__((__bounded__(__minbytes__,1,SHA256_DIGEST_LENGTH)));
void SHA384Init(SHA2_CTX *);
void SHA384Update(SHA2_CTX *, const void *, size_t)
__attribute__((__bounded__(__string__,2,3)));
void SHA384Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA2_CTX *)
__attribute__((__bounded__(__minbytes__,1,SHA384_DIGEST_LENGTH)));
void SHA512Init(SHA2_CTX *);
void SHA512Update(SHA2_CTX *, const void *, size_t)
__attribute__((__bounded__(__string__,2,3)));
void SHA512Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA2_CTX *)
__attribute__((__bounded__(__minbytes__,1,SHA512_DIGEST_LENGTH)));
__END_DECLS
#endif /* _SHA2_H */
+27
View File
@@ -0,0 +1,27 @@
/* PFLINUX compat: <crypto/siphash.h> — SipHash-2-4 (Aumasson–Bernstein)
* API compatible with OpenBSD's SIPHASH_CTX/KEY usage in pf_syncookies.c.
* Implementation: compat/siphash.c (ISC 2026). */
#ifndef _PFK_SIPHASH_H
#define _PFK_SIPHASH_H
#include <linux/types.h>
#define SIPHASH_KEY_LENGTH 16
typedef struct {
__u64 v[2];
} SIPHASH_KEY;
typedef struct {
__u64 v[3];
__u64 total_len;
unsigned char block[8];
unsigned char block_len;
} SIPHASH_CTX;
void SipHash24_Init(SIPHASH_CTX *ctx, const SIPHASH_KEY *key);
void SipHash24_Update(SIPHASH_CTX *ctx, const void *in, __u64 inlen);
void SipHash24_Final(SIPHASH_CTX *ctx, unsigned char *out);
void SipHash24_Generate(const SIPHASH_KEY *key, const void *in, __u64 inlen,
unsigned char *out);
#endif
+72
View File
@@ -0,0 +1,72 @@
/* $OpenBSD: if_pflog.h,v 1.29 2021/01/13 09:13:30 mvs Exp $ */
/*
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* 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 AUTHOR ``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 AUTHOR 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.
*/
#ifndef _NET_IF_PFLOG_H_
#define _NET_IF_PFLOG_H_
#include <sys/queue.h>
#include <net/pfvar.h>
#define PFLOG_RULESET_NAME_SIZE 16
struct pfloghdr {
u_int8_t length;
sa_family_t af;
u_int8_t action;
u_int8_t reason;
char ifname[IFNAMSIZ];
char ruleset[PFLOG_RULESET_NAME_SIZE];
u_int32_t rulenr;
u_int32_t subrulenr;
uid_t uid;
pid_t pid;
uid_t rule_uid;
pid_t rule_pid;
u_int8_t dir;
u_int8_t rewritten;
sa_family_t naf;
u_int8_t pad[1];
struct pf_addr saddr;
struct pf_addr daddr;
u_int16_t sport;
u_int16_t dport;
};
#define PFLOG_HDRLEN sizeof(struct pfloghdr)
/* used to be minus pad, also used as a signature */
#define PFLOG_REAL_HDRLEN PFLOG_HDRLEN
#define PFLOG_OLD_HDRLEN offsetof(struct pfloghdr, pad)
#ifdef _KERNEL
struct pflog_softc {
LIST_ENTRY(pflog_softc) sc_entry;
struct ifnet sc_if; /* the interface */
int sc_unit;
};
#endif /* _KERNEL */
#endif /* _NET_IF_PFLOG_H_ */
+16
View File
@@ -0,0 +1,16 @@
/* PFLINUX compat: <net/if_types.h> — OpenBSD IFT_* constants
* (values must match OpenBSD: they travel in pf_rule/pfk_if ioctls). */
#ifndef _PFK_IF_TYPES_H
#define _PFK_IF_TYPES_H
#define IFT_OTHER 0x1
#define IFT_ETHER 0x6
#define IFT_TOKENRING 0xf
#define IFT_FDDI 0x12
#define IFT_LOOP 0x18
#define IFT_SLIP 0x1f
#define IFT_PPPOINT 0x1e
#define IFT_GIF 0xe6
#define IFT_PFLOG 0xf0
#define IFT_PFSYNC 0xf1
#define IFT_CARP 0xf8
#endif
+5
View File
@@ -0,0 +1,5 @@
/* PFLINUX compat: <net/if_var.h> — ifnet view comes from pfk_if.h */
#ifndef _PFK_IF_VAR_H
#define _PFK_IF_VAR_H
/* intentionally minimal; struct pfk_ifnet is the ifnet */
#endif
+507
View File
@@ -0,0 +1,507 @@
/* $OpenBSD: ifq.h,v 1.44 2025/03/04 01:13:37 dlg Exp $ */
/*
* Copyright (c) 2015 David Gwynne <dlg@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _NET_IFQ_H_
#define _NET_IFQ_H_
struct ifnet;
struct kstat;
struct ifq_ops;
struct ifqueue {
struct ifnet *ifq_if;
struct taskq *ifq_softnet;
union {
void *_ifq_softc;
/*
* a rings sndq is found by looking up an array of pointers.
* by default we only have one sndq and the default drivers
* dont use ifq_softc, so we can borrow it for the map until
* we need to allocate a proper map.
*/
struct ifqueue *_ifq_ifqs[1];
} _ifq_ptr;
#define ifq_softc _ifq_ptr._ifq_softc
#define ifq_ifqs _ifq_ptr._ifq_ifqs
/* mbuf handling */
struct mutex ifq_mtx;
const struct ifq_ops *ifq_ops;
void *ifq_q;
struct mbuf_list ifq_free;
unsigned int ifq_len;
unsigned int ifq_oactive;
/* statistics */
uint64_t ifq_packets;
uint64_t ifq_bytes;
uint64_t ifq_qdrops;
uint64_t ifq_errors;
uint64_t ifq_mcasts;
uint32_t ifq_oactives;
struct kstat *ifq_kstat;
/* work serialisation */
struct mutex ifq_task_mtx;
struct task_list ifq_task_list;
void *ifq_serializer;
struct task ifq_bundle;
/* work to be serialised */
struct task ifq_start;
struct task ifq_restart;
/* properties */
unsigned int ifq_maxlen;
unsigned int ifq_idx;
};
struct ifiqueue {
struct ifnet *ifiq_if;
caddr_t *ifiq_bpfp;
struct taskq *ifiq_softnet;
union {
void *_ifiq_softc;
struct ifiqueue *_ifiq_ifiqs[1];
} _ifiq_ptr;
#define ifiq_softc _ifiq_ptr._ifiq_softc
#define ifiq_ifiqs _ifiq_ptr._ifiq_ifiqs
struct mutex ifiq_mtx;
struct mbuf_list ifiq_ml;
struct task ifiq_task;
unsigned int ifiq_pressure;
/* counters */
uint64_t ifiq_packets;
uint64_t ifiq_bytes;
uint64_t ifiq_fdrops;
uint64_t ifiq_qdrops;
uint64_t ifiq_errors;
uint64_t ifiq_mcasts;
uint64_t ifiq_noproto;
/* number of times a list of packets were put on ifiq_ml */
uint64_t ifiq_enqueues;
/* number of times a list of packets were pulled off ifiq_ml */
uint64_t ifiq_dequeues;
struct kstat *ifiq_kstat;
/* properties */
unsigned int ifiq_idx;
};
#ifdef _KERNEL
#define IFQ_MAXLEN 256
/*
*
* Interface Send Queues
*
* struct ifqueue sits between the network stack and a drivers
* transmission of packets. The high level view is that when the stack
* has finished generating a packet it hands it to a driver for
* transmission. It does this by queueing the packet on an ifqueue and
* notifying the driver to start transmission of the queued packets.
*
* A network device may have multiple contexts for the transmission
* of packets, ie, independent transmit rings. Such a network device,
* represented by a struct ifnet, would then have multiple ifqueue
* structures, each of which maps to an independent transmit ring.
*
* struct ifqueue also provides the point where conditioning of
* traffic (ie, priq and hfsc) is implemented, and provides some
* infrastructure to assist in the implementation of network drivers.
*
* = ifq API
*
* The ifq API provides functions for three distinct consumers:
*
* 1. The network stack
* 2. Traffic QoS/conditioning implementations
* 3. Network drivers
*
* == Network Stack API
*
* The network stack is responsible for initialising and destroying
* the ifqueue structures, changing the traffic conditioner on an
* interface, enqueuing packets for transmission, and notifying
* the driver to start transmission of a particular ifqueue.
*
* === ifq_init()
*
* During if_attach(), the network stack calls ifq_init to initialise
* the ifqueue structure. By default it configures the priq traffic
* conditioner.
*
* === ifq_destroy()
*
* The network stack calls ifq_destroy() during if_detach to tear down
* the ifqueue structure. It frees the traffic conditioner state, and
* frees any mbufs that were left queued.
*
* === ifq_attach()
*
* ifq_attach() is used to replace the current traffic conditioner on
* the ifqueue. All the pending mbufs are removed from the previous
* conditioner and requeued on the new.
*
* === ifq_idx()
*
* ifq_idx() selects a specific ifqueue from the current ifnet
* structure for use in the transmission of the mbuf.
*
* === ifq_enqueue()
*
* ifq_enqueue() attempts to fit an mbuf onto the ifqueue. The
* current traffic conditioner may drop a packet to make space on the
* queue.
*
* === ifq_start()
*
* Once a packet has been successfully queued with ifq_enqueue(),
* the network card is notified with a call to ifq_start().
* Calls to ifq_start() run in the ifqueue serialisation context,
* guaranteeing that only one instance of ifp->if_qstart() will be
* running on behalf of a specific ifqueue in the system at any point
* in time.
*
* == Traffic conditioners API
*
* The majority of interaction between struct ifqueue and a traffic
* conditioner occurs via the callbacks a traffic conditioner provides
* in an instance of struct ifq_ops.
*
* XXX document ifqop_*
*
* The ifqueue API implements the locking on behalf of the conditioning
* implementations so conditioners only have to reject or keep mbufs.
* If something needs to inspect a conditioners internals, the queue lock
* needs to be taken to allow for a consistent or safe view. The queue
* lock may be taken and released with ifq_q_enter() and ifq_q_leave().
*
* === ifq_q_enter()
*
* Code wishing to access a conditioners internals may take the queue
* lock with ifq_q_enter(). The caller must pass a reference to the
* conditioners ifq_ops structure so the infrastructure can ensure the
* caller is able to understand the internals. ifq_q_enter() returns
* a pointer to the conditioners internal structures, or NULL if the
* ifq_ops did not match the current conditioner.
*
* === ifq_q_leave()
*
* The queue lock acquired with ifq_q_enter() is released with
* ifq_q_leave().
*
* === ifq_mfreem() and ifq_mfreeml()
*
* A goal of the API is to avoid freeing an mbuf while mutexes are
* held. Because the ifq API manages the lock on behalf of the backend
* ifqops, the backend should not directly free mbufs. If a conditioner
* backend needs to drop a packet during the handling of ifqop_deq_begin,
* it may free it by calling ifq_mfreem(). This accounts for the drop,
* and schedules the free of the mbuf outside the hold of ifq_mtx.
* ifq_mfreeml() takes an mbuf list as an argument instead.
*
*
* == Network Driver API
*
* The API used by network drivers is mostly documented in the
* ifq_dequeue(9) manpage except for ifq_serialize().
*
* === ifq_serialize()
*
* A driver may run arbitrary work in the ifqueue serialiser context
* via ifq_serialize(). The work to be done is represented by a task
* that has been prepared with task_set.
*
* The work will be run in series with any other work dispatched by
* ifq_start(), ifq_restart(), or other ifq_serialize() calls.
*
* Because the work may be run on another CPU, the lifetime of the
* task and the work it represents can extend beyond the end of the
* call to ifq_serialize() that dispatched it.
*
*
* = ifqueue work serialisation
*
* ifqueues provide a mechanism to dispatch work to be run in a single
* context. Work in this mechanism is represented by task structures.
*
* The tasks are run in a context similar to a taskq serviced by a
* single kernel thread, except the work is run immediately by the
* first CPU that dispatches work. If a second CPU attempts to dispatch
* additional tasks while the first is still running, it will be queued
* to be run by the first CPU. The second CPU will return immediately.
*
* = MP Safe Network Drivers
*
* An MP safe network driver is one in which its start routine can be
* called by the network stack without holding the big kernel lock.
*
* == Attach
*
* A driver advertises its ability to run its start routine without
* the kernel lock by setting the IFXF_MPSAFE flag in ifp->if_xflags
* before calling if_attach(). Advertising an MPSAFE start routine
* also implies that the driver understands that a network card can
* have multiple rings or transmit queues, and therefore provides
* if_qstart function (which takes an ifqueue pointer) instead of an
* if_start function (which takes an ifnet pointer).
*
* If the hardware supports multiple transmit rings, it advertises
* support for multiple rings to the network stack with if_attach_queues()
* after the call to if_attach(). if_attach_queues allocates a struct
* ifqueue for each hardware ring, which can then be initialised by
* the driver with data for each ring.
*
* void drv_start(struct ifqueue *);
*
* void
* drv_attach()
* {
* ...
* ifp->if_xflags = IFXF_MPSAFE;
* ifp->if_qstart = drv_start;
* if_attach(ifp);
*
* if_attach_queues(ifp, DRV_NUM_TX_RINGS);
* for (i = 0; i < DRV_NUM_TX_RINGS; i++) {
* struct ifqueue *ifq = ifp->if_ifqs[i];
* struct drv_tx_ring *ring = &sc->sc_tx_rings[i];
*
* ifq->ifq_softc = ring;
* ring->ifq = ifq;
* }
* }
*
* The network stack will then call ifp->if_qstart via ifq_start()
* to guarantee there is only one instance of that function running
* for each ifq in the system, and to serialise it with other work
* the driver may provide.
*
* == Initialise
*
* When the stack requests an interface be brought up (ie, drv_ioctl()
* is called to handle SIOCSIFFLAGS with IFF_UP set in ifp->if_flags)
* drivers should set IFF_RUNNING in ifp->if_flags, and then call
* ifq_clr_oactive() against each ifq.
*
* == if_start
*
* ifq_start() checks that IFF_RUNNING is set in ifp->if_flags, that
* ifq_is_oactive() does not return true, and that there are pending
* packets to transmit via a call to ifq_len(). Therefore, drivers are
* no longer responsible for doing this themselves.
*
* If a driver should not transmit packets while its link is down, use
* ifq_purge() to flush pending packets from the transmit queue.
*
* Drivers for hardware should use the following pattern to transmit
* packets:
*
* void
* drv_start(struct ifqueue *ifq)
* {
* struct drv_tx_ring *ring = ifq->ifq_softc;
* struct ifnet *ifp = ifq->ifq_if;
* struct drv_softc *sc = ifp->if_softc;
* struct mbuf *m;
* int kick = 0;
*
* if (NO_LINK) {
* ifq_purge(ifq);
* return;
* }
*
* for (;;) {
* if (NO_SPACE(ring)) {
* ifq_set_oactive(ifq);
* break;
* }
*
* m = ifq_dequeue(ifq);
* if (m == NULL)
* break;
*
* if (drv_encap(sc, ring, m) != 0) { // map and fill ring
* m_freem(m);
* continue;
* }
*
* bpf_mtap();
* }
*
* drv_kick(ring); // notify hw of new descriptors on the ring
* }
*
* == Transmission completion
*
* The following pattern should be used for transmit queue interrupt
* processing:
*
* void
* drv_txeof(struct drv_tx_ring *ring)
* {
* struct ifqueue *ifq = ring->ifq;
*
* while (COMPLETED_PKTS(ring)) {
* // unmap packets, m_freem() the mbufs.
* }
*
* if (ifq_is_oactive(ifq))
* ifq_restart(ifq);
* }
*
* == Stop
*
* Bringing an interface down (ie, IFF_UP was cleared in ifp->if_flags)
* should clear IFF_RUNNING in ifp->if_flags, and guarantee the start
* routine is not running before freeing any resources it uses:
*
* void
* drv_down(struct drv_softc *sc)
* {
* struct ifnet *ifp = &sc->sc_if;
* struct ifqueue *ifq;
* int i;
*
* CLR(ifp->if_flags, IFF_RUNNING);
* DISABLE_INTERRUPTS();
*
* for (i = 0; i < sc->sc_num_queues; i++) {
* ifq = ifp->if_ifqs[i];
* ifq_barrier(ifq);
* }
*
* intr_barrier(sc->sc_ih);
*
* FREE_RESOURCES();
*
* for (i = 0; i < sc->sc_num_queues; i++) {
* ifq = ifp->if_ifqs[i];
* ifq_clr_oactive(ifq);
* }
* }
*
*/
struct ifq_ops {
unsigned int (*ifqop_idx)(unsigned int,
const struct mbuf *);
struct mbuf *(*ifqop_enq)(struct ifqueue *, struct mbuf *);
struct mbuf *(*ifqop_deq_begin)(struct ifqueue *, void **);
void (*ifqop_deq_commit)(struct ifqueue *,
struct mbuf *, void *);
void (*ifqop_purge)(struct ifqueue *,
struct mbuf_list *);
void *(*ifqop_alloc)(unsigned int, void *);
void (*ifqop_free)(unsigned int, void *);
};
extern const struct ifq_ops * const ifq_priq_ops;
/*
* Interface send queues.
*/
void ifq_init(struct ifqueue *, struct ifnet *, unsigned int);
void ifq_attach(struct ifqueue *, const struct ifq_ops *, void *);
void ifq_destroy(struct ifqueue *);
void ifq_add_data(struct ifqueue *, struct if_data *);
int ifq_enqueue(struct ifqueue *, struct mbuf *);
void ifq_start(struct ifqueue *);
struct mbuf *ifq_deq_begin(struct ifqueue *);
void ifq_deq_commit(struct ifqueue *, struct mbuf *);
void ifq_deq_rollback(struct ifqueue *, struct mbuf *);
struct mbuf *ifq_dequeue(struct ifqueue *);
int ifq_hdatalen(struct ifqueue *);
void ifq_init_maxlen(struct ifqueue *, unsigned int);
void ifq_mfreem(struct ifqueue *, struct mbuf *);
void ifq_mfreeml(struct ifqueue *, struct mbuf_list *);
unsigned int ifq_purge(struct ifqueue *);
void *ifq_q_enter(struct ifqueue *, const struct ifq_ops *);
void ifq_q_leave(struct ifqueue *, void *);
void ifq_serialize(struct ifqueue *, struct task *);
void ifq_barrier(struct ifqueue *);
void ifq_set_oactive(struct ifqueue *);
void ifq_deq_set_oactive(struct ifqueue *);
int ifq_deq_sleep(struct ifqueue *, struct mbuf **, int, int,
const char *, volatile unsigned int *,
volatile unsigned int *);
#define ifq_len(_ifq) READ_ONCE((_ifq)->ifq_len)
#define ifq_empty(_ifq) (ifq_len(_ifq) == 0)
static inline int
ifq_is_priq(struct ifqueue *ifq)
{
return (ifq->ifq_ops == ifq_priq_ops);
}
static inline void
ifq_clr_oactive(struct ifqueue *ifq)
{
ifq->ifq_oactive = 0;
}
static inline unsigned int
ifq_is_oactive(struct ifqueue *ifq)
{
return (ifq->ifq_oactive);
}
static inline void
ifq_restart(struct ifqueue *ifq)
{
ifq_serialize(ifq, &ifq->ifq_restart);
}
static inline unsigned int
ifq_idx(struct ifqueue *ifq, unsigned int nifqs, const struct mbuf *m)
{
return ((*ifq->ifq_ops->ifqop_idx)(nifqs, m));
}
/* ifiq */
void ifiq_init(struct ifiqueue *, struct ifnet *, unsigned int);
void ifiq_destroy(struct ifiqueue *);
int ifiq_input(struct ifiqueue *, struct mbuf_list *);
int ifiq_enqueue_qlim(struct ifiqueue *, struct mbuf *,
unsigned int);
void ifiq_add_data(struct ifiqueue *, struct if_data *);
#define ifiq_len(_ifiq) READ_ONCE(ml_len(&(_ifiq)->ifiq_ml))
#define ifiq_empty(_ifiq) (ifiq_len(_ifiq) == 0)
static inline int
ifiq_enqueue(struct ifiqueue *ifiq, struct mbuf *m)
{
return ifiq_enqueue_qlim(ifiq, m, 0);
}
#endif /* _KERNEL */
#endif /* _NET_IFQ_H_ */
+75
View File
@@ -0,0 +1,75 @@
/* PFLINUX compat: <net/radix.h> — OpenBSD 8.0 radix structures/API
* (rn_*), cleaned of BSD-only syntax. Implementation: compat/radix.c
* (ported from OpenBSD 8.0 sys/net/radix.c, task T10). */
#ifndef _PFK_RADIX_H
#define _PFK_RADIX_H
#include <linux/types.h>
struct radix_mask;
struct radix_node {
struct radix_mask *rn_mklist;
struct radix_node *rn_p;
short rn_b;
char rn_bmask;
u_char rn_flags;
#define RNF_NORMAL 1
#define RNF_ROOT 2
#define RNF_ACTIVE 4
union {
struct {
caddr_t rn_Key;
caddr_t rn_Mask;
struct radix_node *rn_Dupedkey;
} rn_leaf;
struct {
int rn_Off;
struct radix_node *rn_L;
struct radix_node *rn_R;
} rn_node;
} rn_u;
};
#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey
#define rn_key rn_u.rn_leaf.rn_Key
#define rn_mask rn_u.rn_leaf.rn_Mask
#define rn_off rn_u.rn_node.rn_Off
#define rn_l rn_u.rn_node.rn_L
#define rn_r rn_u.rn_node.rn_R
struct radix_mask {
short rm_b;
char rm_unused;
u_char rm_flags;
struct radix_mask *rm_mklist;
union {
caddr_t rmu_mask;
struct radix_node *rmu_leaf;
} rm_rmu;
int rm_refs;
};
#define rm_mask rm_rmu.rmu_mask
#define rm_leaf rm_rmu.rmu_leaf
struct radix_node_head {
struct radix_node *rnh_treetop;
int rnh_addrsize;
int rnh_pktsize;
struct radix_node rnh_nodes[3];
u_int rnh_rtableid;
};
void rn_init(unsigned int);
int rn_inithead(void **, int);
int rn_walktree(struct radix_node_head *,
int (*)(struct radix_node *, void *, u_int), void *);
struct radix_node *rn_addroute(void *, void *, struct radix_node_head *,
struct radix_node [2], u_int8_t);
struct radix_node *rn_delete(void *, void *, struct radix_node_head *,
struct radix_node *);
struct radix_node *rn_lookup(void *, void *, struct radix_node_head *);
struct radix_node *rn_match(void *, struct radix_node_head *);
#endif /* _PFK_RADIX_H_ */
+82
View File
@@ -0,0 +1,82 @@
/* $OpenBSD: rtable.h,v 1.36 2025/07/15 09:55:49 dlg Exp $ */
/*
* Copyright (c) 2014-2016 Martin Pieuchot
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _NET_RTABLE_H_
#define _NET_RTABLE_H_
#include <sys/rwlock.h>
struct art;
/*
* Locks used to protect struct members in this file:
* I immutable after creation
* N net lock
*/
struct rtable {
struct rwlock r_lock;
struct art *r_art; /* [I] */
unsigned int r_off; /* [I] Offset of key in bytes */
struct sockaddr *r_source; /* [N] use optional src addr */
};
/*
* Newer routing table implementation based on ART (Allotment Routing
* Table).
*/
#define rt_key(rt) ((rt)->rt_dest)
#define rt_plen(rt) ((rt)->rt_plen)
#define RT_ROOT(rt) (0)
int rtable_satoplen(sa_family_t, const struct sockaddr *);
void rtable_init(void);
int rtable_exists(unsigned int);
int rtable_empty(unsigned int);
int rtable_add(unsigned int);
unsigned int rtable_l2(unsigned int);
unsigned int rtable_loindex(unsigned int);
void rtable_l2set(unsigned int, unsigned int, unsigned int);
int rtable_setsource(unsigned int, int, struct sockaddr *);
struct sockaddr *rtable_getsource(unsigned int, int);
void rtable_clearsource(unsigned int, struct sockaddr *);
struct rtentry *rtable_lookup(unsigned int, const struct sockaddr *,
const struct sockaddr *, const struct sockaddr *, uint8_t);
struct rtentry *rtable_match(unsigned int, const struct sockaddr *,
uint32_t *);
struct rtentry *rtable_iterate(struct rtentry *);
int rtable_insert(unsigned int, struct sockaddr *,
const struct sockaddr *, const struct sockaddr *, uint8_t,
struct rtentry *);
int rtable_delete(unsigned int, const struct sockaddr *,
const struct sockaddr *, struct rtentry *);
int rtable_walk(unsigned int, sa_family_t, struct rtentry **,
int (*)(struct rtentry *, void *, unsigned int), void *);
int rtable_read(unsigned int, sa_family_t,
int (*)(const struct rtentry *, void *, unsigned int),
void *);
int rtable_mpath_capable(unsigned int, sa_family_t);
int rtable_mpath_reprio(unsigned int, struct sockaddr *, int,
uint8_t, struct rtentry *);
#endif /* _NET_RTABLE_H_ */
+53
View File
@@ -0,0 +1,53 @@
/* PFLINUX compat: <net/toeplitz.h> — software Toeplitz hash (RFC 3305)
* with the OpenBSD API shape used by PF (global cache + stoeplitz_* macros).
* Implementation: compat/toeplitz.c (uses kernel crypto_shash "sha256"). */
#ifndef _PFK_TOEPLITZ_H
#define _PFK_TOEPLITZ_H
#include <linux/types.h>
#define TOEPLITZ_KEY_LEN 40
struct stoeplitz_cache {
u8 key[TOEPLITZ_KEY_LEN];
u8 keyhash[32]; /* SHA256(key) */
int initialized;
};
extern struct stoeplitz_cache *stoeplitz_cache;
void stoeplitz_init(void);
void stoeplitz_cache_init(struct stoeplitz_cache *, const u8 *key);
uint16_t stoeplitz_hash_ip4(const struct stoeplitz_cache *,
const struct in_addr *, const struct in_addr *);
uint16_t stoeplitz_hash_ip4port(const struct stoeplitz_cache *,
const struct in_addr *, const struct in_addr *,
u16, u16);
uint16_t stoeplitz_hash_ip6(const struct stoeplitz_cache *,
const struct in6_addr *, const struct in6_addr *);
uint16_t stoeplitz_hash_ip6port(const struct stoeplitz_cache *,
const struct in6_addr *, const struct in6_addr *,
u16, u16);
uint16_t stoeplitz_hash_eaddr(const struct stoeplitz_cache *,
const u8 *);
uint16_t stoeplitz_hash_n16(const struct stoeplitz_cache *, u16);
uint16_t stoeplitz_hash_n32(const struct stoeplitz_cache *, u32);
uint16_t stoeplitz_hash_h16(const struct stoeplitz_cache *, u16);
uint16_t stoeplitz_hash_h32(const struct stoeplitz_cache *, u32);
uint16_t stoeplitz_hash_h64(const struct stoeplitz_cache *, u64);
#define stoeplitz_n32(_n32) stoeplitz_hash_n32(stoeplitz_cache, (_n32))
#define stoeplitz_h16(_h16) stoeplitz_hash_h16(stoeplitz_cache, (_h16))
#define stoeplitz_h32(_h32) stoeplitz_hash_h32(stoeplitz_cache, (_h32))
#define stoeplitz_h64(_h64) stoeplitz_hash_h64(stoeplitz_cache, (_h64))
#define stoeplitz_ip4(_sa4, _da4) \
stoeplitz_hash_ip4(stoeplitz_cache, (_sa4), (_da4))
#define stoeplitz_ip4port(_sa4, _da4, _sp, _dp) \
stoeplitz_hash_ip4port(stoeplitz_cache, (_sa4), (_da4), (_sp), (_dp))
#define stoeplitz_ip6(_sa6, _da6) \
stoeplitz_hash_ip6(stoeplitz_cache, (_sa6), (_da6))
#define stoeplitz_ip6port(_sa6, _da6, _sp, _dp) \
stoeplitz_hash_ip6port(stoeplitz_cache, (_sa6), (_da6), (_sp), (_dp))
#define stoeplitz_eaddr(_ea) \
stoeplitz_hash_eaddr(stoeplitz_cache, (_ea))
#endif
+13
View File
@@ -0,0 +1,13 @@
/* PFLINUX compat: <netinet/in.h> */
#ifndef _PFK_NETINET_IN_H
#define _PFK_NETINET_IN_H
#include <linux/in.h>
#include <linux/in6.h>
/* BSD IP-level option numbers (Linux uapi uses different values) */
#define PF_IP_OPTIONS 1
#define PF_IP_RECORD_ROUTE 7
#define PF_IP_TIMESTAMP 68
#ifndef INADDR_MULTICAST
#define INADDR_MULTICAST 0xe0000000U
#endif
#endif
+179
View File
@@ -0,0 +1,179 @@
/* $OpenBSD: _endian.h,v 1.8 2018/01/11 23:13:37 dlg Exp $ */
/*-
* Copyright (c) 1997 Niklas Hallqvist. All rights reserved.
*
* 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 AUTHOR ``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 AUTHOR 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.
*/
/*
* Internal endianness macros. This pulls in <machine/endian.h> to
* get the correct setting direction for the platform and sets internal
* ('__' prefix) macros appropriately.
*/
#ifndef _SYS__ENDIAN_H_
#define _SYS__ENDIAN_H_
#include <sys/_types.h>
#define __FROM_SYS__ENDIAN
#include <machine/endian.h>
#undef __FROM_SYS__ENDIAN
#define _LITTLE_ENDIAN 1234
#define _BIG_ENDIAN 4321
#define _PDP_ENDIAN 3412
/* Note that these macros evaluate their arguments several times. */
#define __swap16gen(x) \
(__uint16_t)(((__uint16_t)(x) & 0xffU) << 8 | ((__uint16_t)(x) & 0xff00U) >> 8)
#define __swap32gen(x) \
(__uint32_t)(((__uint32_t)(x) & 0xff) << 24 | \
((__uint32_t)(x) & 0xff00) << 8 | ((__uint32_t)(x) & 0xff0000) >> 8 |\
((__uint32_t)(x) & 0xff000000) >> 24)
#define __swap64gen(x) \
(__uint64_t)((((__uint64_t)(x) & 0xff) << 56) | \
((__uint64_t)(x) & 0xff00ULL) << 40 | \
((__uint64_t)(x) & 0xff0000ULL) << 24 | \
((__uint64_t)(x) & 0xff000000ULL) << 8 | \
((__uint64_t)(x) & 0xff00000000ULL) >> 8 | \
((__uint64_t)(x) & 0xff0000000000ULL) >> 24 | \
((__uint64_t)(x) & 0xff000000000000ULL) >> 40 | \
((__uint64_t)(x) & 0xff00000000000000ULL) >> 56)
#ifndef __HAVE_MD_SWAP
static __inline __uint16_t
__swap16md(__uint16_t x)
{
return (__swap16gen(x));
}
static __inline __uint32_t
__swap32md(__uint32_t x)
{
return (__swap32gen(x));
}
static __inline __uint64_t
__swap64md(__uint64_t x)
{
return (__swap64gen(x));
}
#endif
#define __swap16(x) \
(__uint16_t)(__builtin_constant_p(x) ? __swap16gen(x) : __swap16md(x))
#define __swap32(x) \
(__uint32_t)(__builtin_constant_p(x) ? __swap32gen(x) : __swap32md(x))
#define __swap64(x) \
(__uint64_t)(__builtin_constant_p(x) ? __swap64gen(x) : __swap64md(x))
#if _BYTE_ORDER == _LITTLE_ENDIAN
#define _QUAD_HIGHWORD 1
#define _QUAD_LOWWORD 0
#define __htobe16 __swap16
#define __htobe32 __swap32
#define __htobe64 __swap64
#define __htole16(x) ((__uint16_t)(x))
#define __htole32(x) ((__uint32_t)(x))
#define __htole64(x) ((__uint64_t)(x))
#ifdef _KERNEL
#ifdef __HAVE_MD_SWAPIO
#define __bemtoh16(_x) __mswap16(_x)
#define __bemtoh32(_x) __mswap32(_x)
#define __bemtoh64(_x) __mswap64(_x)
#define __htobem16(_x, _v) __swapm16((_x), (_v))
#define __htobem32(_x, _v) __swapm32((_x), (_v))
#define __htobem64(_x, _v) __swapm64((_x), (_v))
#endif /* __HAVE_MD_SWAPIO */
#endif /* _KERNEL */
#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
#if _BYTE_ORDER == _BIG_ENDIAN
#define _QUAD_HIGHWORD 0
#define _QUAD_LOWWORD 1
#define __htobe16(x) ((__uint16_t)(x))
#define __htobe32(x) ((__uint32_t)(x))
#define __htobe64(x) ((__uint64_t)(x))
#define __htole16 __swap16
#define __htole32 __swap32
#define __htole64 __swap64
#ifdef _KERNEL
#ifdef __HAVE_MD_SWAPIO
#define __lemtoh16(_x) __mswap16(_x)
#define __lemtoh32(_x) __mswap32(_x)
#define __lemtoh64(_x) __mswap64(_x)
#define __htolem16(_x, _v) __swapm16((_x), (_v))
#define __htolem32(_x, _v) __swapm32((_x), (_v))
#define __htolem64(_x, _v) __swapm64((_x), (_v))
#endif /* __HAVE_MD_SWAPIO */
#endif /* _KERNEL */
#endif /* _BYTE_ORDER == _BIG_ENDIAN */
#ifdef _KERNEL
/*
* Fill in the __hto[bl]em{16,32,64} and __[bl]emtoh{16,32,64} macros
* that haven't been defined yet
*/
#ifndef __bemtoh16
#define __bemtoh16(_x) __htobe16(*(__uint16_t *)(_x))
#define __bemtoh32(_x) __htobe32(*(__uint32_t *)(_x))
#define __bemtoh64(_x) __htobe64(*(__uint64_t *)(_x))
#endif
#ifndef __htobem16
#define __htobem16(_x, _v) (*(__uint16_t *)(_x) = __htobe16(_v))
#define __htobem32(_x, _v) (*(__uint32_t *)(_x) = __htobe32(_v))
#define __htobem64(_x, _v) (*(__uint64_t *)(_x) = __htobe64(_v))
#endif
#ifndef __lemtoh16
#define __lemtoh16(_x) __htole16(*(__uint16_t *)(_x))
#define __lemtoh32(_x) __htole32(*(__uint32_t *)(_x))
#define __lemtoh64(_x) __htole64(*(__uint64_t *)(_x))
#endif
#ifndef __htolem16
#define __htolem16(_x, _v) (*(__uint16_t *)(_x) = __htole16(_v))
#define __htolem32(_x, _v) (*(__uint32_t *)(_x) = __htole32(_v))
#define __htolem64(_x, _v) (*(__uint64_t *)(_x) = __htole64(_v))
#endif
#endif /* _KERNEL */
#endif /* _SYS__ENDIAN_H_ */
+7
View File
@@ -0,0 +1,7 @@
/* PFLINUX compat: <sys/_null.h> */
#ifndef _SYS__NULL_H_
#define _SYS__NULL_H_
#ifndef NULL
#define NULL 0L
#endif
#endif
+34
View File
@@ -0,0 +1,34 @@
/* PFLINUX compat: <sys/cdefs.h> minimal for queue.h/tree.h */
#ifndef _PFK_CDEFS_H
#define _PFK_CDEFS_H
#include <linux/compiler.h>
#define __BEGIN_DECLS
#define __END_DECLS
#ifndef __aligned
#define __aligned(x) __attribute__((__aligned__(x)))
#endif
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
#ifndef __dead
#define __dead __attribute__((__noreturn__))
#endif
#ifndef __predict_false
#define __predict_false(x) unlikely(x)
#endif
#ifndef __predict_true
#define __predict_true(x) likely(x)
#endif
#ifndef __arraycount
#define __arraycount(a) (sizeof(a)/sizeof((a)[0]))
#endif
#ifndef __predict
#define __predict(x, y) ((y) ? likely(x) : unlikely(x))
#endif
#ifndef __restrict
#define __restrict
#endif
#endif
+6
View File
@@ -0,0 +1,6 @@
/* PFLINUX compat: <sys/endian.h> */
#ifndef _PFK_SYS_ENDIAN_H
#define _PFK_SYS_ENDIAN_H
#include <linux/byteorder/generic.h>
#include <linux/byteorder/little_endian.h>
#endif
+10
View File
@@ -0,0 +1,10 @@
/* PFLINUX compat: <sys/param.h> */
#ifndef _PFK_PARAM_H
#define _PFK_PARAM_H
#include <linux/limits.h>
#define MAXHOSTNAMELEN 64
#define NOFILE 256
#define BSD 20260101
#define BSD_VERSION BSD
#define NETBSD 0
#endif
+633
View File
@@ -0,0 +1,633 @@
/* $OpenBSD: queue.h,v 1.47 2026/06/12 01:04:42 millert Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
#include <sys/_null.h>
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues and XOR simple queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* An XOR simple queue is used in the same way as a regular simple queue.
* The difference is that the head structure also includes a "cookie" that
* is XOR'd with the queue pointer (first, last or next) to generate the
* real pointer value.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALID ((void *)-1)
#define _Q_INVALIDATE(a) (a) = _Q_INVALID
#else
#define _Q_INVALIDATE(a)
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST(head); \
(var) && ((tvar) = SLIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
\
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
} \
_Q_INVALIDATE((elm)->field.sle_next); \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods.
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST(head); \
(var) && ((tvar) = LIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SIMPLEQ_FIRST(head); \
(var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
== NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_CONCAT(head1, head2) do { \
if (!SIMPLEQ_EMPTY((head2))) { \
*(head1)->sqh_last = (head2)->sqh_first; \
(head1)->sqh_last = (head2)->sqh_last; \
SIMPLEQ_INIT((head2)); \
} \
} while (0)
/*
* XOR Simple queue definitions.
*/
#define XSIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqx_first; /* first element */ \
struct type **sqx_last; /* addr of last next element */ \
unsigned long sqx_cookie; \
}
#define XSIMPLEQ_ENTRY(type) \
struct { \
struct type *sqx_next; /* next element */ \
}
/*
* XOR Simple queue access methods.
*/
#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
(unsigned long)(ptr)))
#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
#define XSIMPLEQ_END(head) NULL
#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
#define XSIMPLEQ_FOREACH(var, head, field) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) != XSIMPLEQ_END(head); \
(var) = XSIMPLEQ_NEXT(head, var, field))
#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
(var) = (tvar))
/*
* XOR Simple queue functions.
*/
#define XSIMPLEQ_INIT(head) do { \
arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
(head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqx_next = (head)->sqx_first) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
(head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
(elm)->field.sqx_next)->field.sqx_next) \
== XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = \
XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* Tail queue access methods.
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_NEXT(var, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
} \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first; /* first element */ \
struct type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue access methods.
*/
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_END(head) NULL
#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_FOREACH(var, head, field) \
for ((var) = STAILQ_FIRST(head); \
(var) != STAILQ_END(head); \
(var) = STAILQ_NEXT(var, field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST(head); \
(var) && ((tvar) = STAILQ_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((listelm), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((listelm), field) = (elm); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_REMOVE(head, elm, type, field) do { \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->stqh_first; \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
} while (0)
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? NULL : \
((struct type *)(void *) \
((char *)((head)->stqh_last) - offsetof(struct type, field))))
#endif /* !_SYS_QUEUE_H_ */
+38
View File
@@ -0,0 +1,38 @@
/* PFLINUX compat: <sys/refcnt.h> — refcount_t wrapper with OpenBSD API */
#ifndef _PFK_REFCNT_H
#define _PFK_REFCNT_H
#include <linux/refcount.h>
struct refcnt { refcount_t rc; };
#define REFCNT_INITIALIZER { .rc = REFCNT_INIT }
static inline void refcnt_init(struct refcnt *r, unsigned int v)
{
refcount_set(&r->rc, v ? (int)v : 1);
}
static inline unsigned int refcnt_value(const struct refcnt *r)
{
return refcount_read((refcount_t *)&r->rc);
}
static inline void refcnt_take(struct refcnt *r)
{
refcount_inc(&r->rc);
}
/* returns true if ref was valid and taken (OpenBSD refcnt_take_if) */
static inline bool refcnt_take_not0(struct refcnt *r)
{
return refcount_inc_not_zero(&r->rc);
}
static inline unsigned int refcnt_rele(struct refcnt *r)
{
return (unsigned int)refcount_dec_and_test(&r->rc) ?
refcnt_value(r) : refcnt_value(r) + 1;
}
static inline unsigned int refcnt_rele_wake(struct refcnt *r)
{
return refcnt_rele(r);
}
static inline void refcnt_finalize(struct refcnt *r, const void *unused)
{
}
#endif
+46
View File
@@ -0,0 +1,46 @@
/* PFLINUX compat: <sys/socket.h> — BSD sockaddrs stay Linux-layout;
* sa_len fields are removed by the staging sed (see PORTING.md).
* Provides BSD sockaddr accessor macros + address family constants. */
#ifndef _PFK_SOCKET_H
#define _PFK_SOCKET_H
#include <linux/types.h>
struct pfk_sockaddr_union {
struct sockaddr_storage ss;
};
#define sintosa(x) ((struct sockaddr_in *)(void *)(x))
#define sin6tosa(x) ((struct sockaddr_in6 *)(void *)(x))
#define sa_tosa(x) ((struct sockaddr *)(void *)(x))
#define satosa(x) ((struct sockaddr *)(void *)(x))
#define satoxp(x) ((void *)(x)) /* unused; keep symbol */
#define SA_LEN(x) (((x)->sa_family == AF_INET) ? \
sizeof(struct sockaddr_in) : \
((x)->sa_family == AF_INET6) ? \
sizeof(struct sockaddr_in6) : 16)
#define PFK_SA(x) ((struct sockaddr *)(x))
#define PFK_INA(x) (&((struct sockaddr_in *)(x))->sin_addr)
#define PFK_SA6(x) ((struct sockaddr_in6 *)(x))
/* BSD sin_port/sin_addr == Linux: both network byte order fields */
#ifndef SIN_IS_PRIVATE
#define SIN_IS_PRIVATE 1
#endif
/* AF_INET6 == 10 on both sides */
#ifndef AF_LINK
#define AF_LINK 18 /* OpenBSD value; used by pf for link sa */
#endif
static inline int pfk_sa_cmp(const struct sockaddr *a, const struct sockaddr *b)
{
if (a->sa_family != b->sa_family)
return 1;
switch (a->sa_family) {
case AF_INET:
return memcmp(sintosa(a), sintosa(b), sizeof(struct sockaddr_in));
case AF_INET6:
return memcmp(sin6tosa(a), sin6tosa(b), sizeof(struct sockaddr_in6));
}
return 1;
}
#endif
+9
View File
@@ -0,0 +1,9 @@
/* PFLINUX compat: <sys/syslimits.h> */
#ifndef _PFK_SYSLIMITS_H
#define _PFK_SYSLIMITS_H
#include <linux/limits.h>
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#define MAXSYMLINKS 8
#endif
+17
View File
@@ -0,0 +1,17 @@
/* PFLINUX compat: <sys/timeout.h> */
#ifndef _PFK_TIMEOUT_H
#define _PFK_TIMEOUT_H
#include <linux/timer.h>
#include <linux/workqueue.h>
typedef void (timeout_fn)(void *);
struct timeout {
struct timer_list timer;
struct work_struct work;
timeout_fn *fn;
void *arg;
unsigned long deadline_jif;
int period_ms;
int pending;
int running;
};
#endif
File diff suppressed because it is too large. Load diff
+6
View File
@@ -0,0 +1,6 @@
/* PFLINUX compat: <sys/types.h> */
#ifndef _PFK_SYS_TYPES_H
#define _PFK_SYS_TYPES_H
#include <linux/types.h>
typedef unsigned long u_long;
#endif
File diff suppressed because it is too large. Load diff
+689
View File
@@ -0,0 +1,689 @@
/* $OpenBSD: pfvar_priv.h,v 1.43 2026/09/10 12:28:04 deraadt Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
* Copyright (c) 2002 - 2013 Henning Brauer <henning@openbsd.org>
* Copyright (c) 2016 Alexander Bluhm <bluhm@openbsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - 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 COPYRIGHT HOLDERS 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
* COPYRIGHT HOLDERS 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.
*
*/
#ifndef _NET_PFVAR_PRIV_H_
#define _NET_PFVAR_PRIV_H_
#ifdef _KERNEL
#include <sys/rwlock.h>
#include <sys/mutex.h>
#include <sys/pclock.h>
#include <sys/percpu.h>
/*
* Locks used to protect struct members in this file:
* L pf_inp_mtx link pf to inp mutex
*/
struct pfsync_deferral;
struct kstat;
/*
* PF state links
*
* This is used to augment a struct pf_state so it can be
* tracked/referenced by the state and source address limiter things.
* Each limiter maintains a list of the states they "own", and these
* state links are what the limiters use to wire a state into their
* lists.
*
* Without PF state links, the pf_state struct would have to grow
* a lot to support a feature that may not be used.
*
* pfl_entry is used by the pools to add states to their list.
* pfl_state allows the pools to get from their list of states to
* the states themselves.
*
* pfl_link allows operations on states (well, delete) to be able
* to quickly locate the pf_state_link struct so they can be unwired
* from the pools.
*/
#define PF_STATE_LINK_TYPE_STATELIM 1
#define PF_STATE_LINK_TYPE_SOURCELIM 2
struct pf_state_link {
/* used by source/state pools to get to states */
TAILQ_ENTRY(pf_state_link) pfl_link;
/* used by pf_state to get to source/state pools */
SLIST_ENTRY(pf_state_link) pfl_linkage;
struct pf_state *pfl_state;
unsigned int pfl_type;
};
TAILQ_HEAD(pf_state_link_list, pf_state_link);
SLIST_HEAD(pf_state_linkage, pf_state_link);
/*
* pf state items - links from pf_state_key to pf_states
*/
struct pf_state_item {
TAILQ_ENTRY(pf_state_item)
si_entry;
struct pf_state *si_st;
};
TAILQ_HEAD(pf_statelisthead, pf_state_item);
/*
* pf state keys - look up states by address
*/
struct pf_state_key {
struct pf_addr addr[2];
u_int16_t port[2];
u_int16_t rdomain;
u_int16_t hash;
sa_family_t af;
u_int8_t proto;
RBT_ENTRY(pf_state_key) sk_entry;
struct pf_statelisthead sk_states;
struct pf_state_key *sk_reverse;
struct inpcb *sk_inp; /* [L] */
pf_refcnt_t sk_refcnt;
u_int8_t sk_removed;
};
RBT_HEAD(pf_state_tree, pf_state_key);
RBT_PROTOTYPE(pf_state_tree, pf_state_key, sk_entry, pf_state_compare_key);
#define PF_REVERSED_KEY(key, family) \
((key[PF_SK_WIRE]->af != key[PF_SK_STACK]->af) && \
(key[PF_SK_WIRE]->af != (family)))
/*
* pf state
*
* Protection/ownership of pf_state members:
* I immutable after pf_state_insert()
* M pf_state mtx
* P PF_STATE_LOCK
* S pfsync
* L pf_state_list
* g pf_purge gc
*/
struct pf_state {
u_int64_t id; /* [I] */
u_int32_t creatorid; /* [I] */
u_int8_t direction; /* [I] */
u_int8_t pad[3];
TAILQ_ENTRY(pf_state) sync_list; /* [S] */
struct pfsync_deferral *sync_defer; /* [S] */
TAILQ_ENTRY(pf_state) entry_list; /* [L] */
SLIST_ENTRY(pf_state) gc_list; /* [g] */
RBT_ENTRY(pf_state) entry_id; /* [P] */
struct pf_state_peer src;
struct pf_state_peer dst;
struct pf_rule_slist match_rules; /* [I] */
union pf_rule_ptr rule; /* [I] */
union pf_rule_ptr anchor; /* [I] */
union pf_rule_ptr natrule; /* [I] */
struct pf_addr rt_addr; /* [I] */
struct pf_sn_head src_nodes; /* [I] */
struct pf_state_key *key[2]; /* [I] stack and wire */
struct pfi_kif *kif; /* [I] */
struct mutex mtx;
pf_refcnt_t refcnt;
u_int64_t packets[2];
u_int64_t bytes[2];
int32_t creation; /* [I] */
int32_t expire;
int32_t pfsync_time; /* [S] */
int rtableid[2]; /* [I] stack and wire */
u_int16_t qid; /* [I] */
u_int16_t pqid; /* [I] */
u_int16_t tag; /* [I] */
u_int16_t state_flags; /* [M] */
u_int8_t log; /* [I] */
u_int8_t timeout;
u_int8_t sync_state; /* [S] PFSYNC_S_x */
u_int8_t sync_updates; /* [S] */
u_int8_t min_ttl; /* [I] */
u_int8_t set_tos; /* [I] */
u_int8_t set_prio[2]; /* [I] */
u_int16_t max_mss; /* [I] */
u_int16_t if_index_in; /* [I] */
u_int16_t if_index_out; /* [I] */
u_int16_t delay; /* [I] */
u_int8_t rt; /* [I] */
uint8_t statelim;
uint8_t sourcelim;
struct pf_state_linkage linkage;
};
RBT_HEAD(pf_state_tree_id, pf_state);
RBT_PROTOTYPE(pf_state_tree_id, pf_state, entry_id, pf_state_compare_id);
extern struct pf_state_tree_id tree_id;
/*
* states are linked into a global list to support the following
* functionality:
*
* - garbage collection
* - pfsync bulk send operations
* - bulk state fetches via the DIOCGETSTATES ioctl
* - bulk state clearing via the DIOCCLRSTATES ioctl
*
* states are inserted into the global pf_state_list once it has also
* been successfully added to the various trees that make up the state
* table. states are only removed from the pf_state_list by the garbage
* collection process.
*
* the pf_state_list head and tail pointers (ie, the pfs_list TAILQ_HEAD
* structure) and the pointers between the entries on the pf_state_list
* are locked separately. at a high level, this allows for insertion
* of new states into the pf_state_list while other contexts (eg, the
* ioctls) are traversing the state items in the list. for garbage
* collection to remove items from the pf_state_list, it has to exclude
* both modifications to the list head and tail pointers, and traversal
* of the links between the states.
*
* the head and tail pointers are protected by a mutex. the pointers
* between states are protected by an rwlock.
*
* because insertions are only made to the end of the list, if we get
* a snapshot of the head and tail of the list and prevent modifications
* to the links between states, we can safely traverse between the
* head and tail entries. subsequent insertions can add entries after
* our view of the tail, but we don't look past our view.
*
* if both locks must be taken, the rwlock protecting the links between
* states is taken before the mutex protecting the head and tail
* pointer.
*
* insertion into the list follows this pattern:
*
* // serialise list head/tail modifications
* mtx_enter(&pf_state_list.pfs_mtx);
* TAILQ_INSERT_TAIL(&pf_state_list.pfs_list, state, entry_list);
* mtx_leave(&pf_state_list.pfs_mtx);
*
* traversal of the list:
*
* // lock against the gc removing an item from the list
* rw_enter_read(&pf_state_list.pfs_rwl);
*
* // get a snapshot view of the ends of the list
* mtx_enter(&pf_state_list.pfs_mtx);
* head = TAILQ_FIRST(&pf_state_list.pfs_list);
* tail = TAILQ_LAST(&pf_state_list.pfs_list, pf_state_queue);
* mtx_leave(&pf_state_list.pfs_mtx);
*
* state = NULL;
* next = head;
*
* while (state != tail) {
* state = next;
* next = TAILQ_NEXT(state, entry_list);
*
* // look at the state
* }
*
* rw_exit_read(&pf_state_list.pfs_rwl);
*
* removing an item from the list:
*
* // wait for iterators (readers) to get out
* rw_enter_write(&pf_state_list.pfs_rwl);
*
* // serialise list head/tail modifications
* mtx_enter(&pf_state_list.pfs_mtx);
* TAILQ_REMOVE(&pf_state_list.pfs_list, state, entry_list);
* mtx_leave(&pf_state_list.pfs_mtx);
*
* rw_exit_write(&pf_state_list.pfs_rwl);
*
* the lock ordering for pf_state_list locks and the rest of the pf
* locks are:
*
* 1. KERNEL_LOCK
* 2. NET_LOCK
* 3. pf_state_list.pfs_rwl
* 4. PF_LOCK
* 5. PF_STATE_LOCK
* 6. pf_state_list.pfs_mtx
*/
struct pf_state_list {
/* the list of states in the system */
struct pf_state_queue pfs_list;
/* serialise pfs_list head/tail access */
struct mutex pfs_mtx;
/* serialise access to pointers between pfs_list entries */
struct rwlock pfs_rwl;
};
#define PF_STATE_LIST_INITIALIZER(_pfs) { \
.pfs_list = TAILQ_HEAD_INITIALIZER(_pfs.pfs_list), \
.pfs_mtx = MUTEX_INITIALIZER(IPL_SOFTNET), \
.pfs_rwl = RWLOCK_INITIALIZER("pfstates"), \
}
/*
* State limiter
*/
struct pf_statelim {
RBT_ENTRY(pf_statelim) pfstlim_id_tree;
RBT_ENTRY(pf_statelim) pfstlim_nm_tree;
TAILQ_ENTRY(pf_statelim) pfstlim_list;
struct kstat *pfstlim_ks;
uint32_t pfstlim_id;
char pfstlim_nm[PF_STATELIM_NAME_LEN];
/* config */
unsigned int pfstlim_limit;
struct {
unsigned int limit;
unsigned int seconds;
} pfstlim_rate;
/* run state */
struct pc_lock pfstlim_lock;
/* rate limiter */
uint64_t pfstlim_rate_ts;
uint64_t pfstlim_rate_token;
uint64_t pfstlim_rate_bucket;
unsigned int pfstlim_inuse;
struct pf_state_link_list pfstlim_states;
/* counters */
struct {
uint64_t admitted;
uint64_t hardlimited;
uint64_t ratelimited;
} pfstlim_counters;
struct {
time_t created;
time_t updated;
time_t cleared;
} pfstlim_timestamps;
};
RBT_HEAD(pf_statelim_id_tree, pf_statelim);
RBT_PROTOTYPE(pf_statelim_id_tree, pf_statelim, pfstlim_id_tree, cmp);
RBT_HEAD(pf_statelim_nm_tree, pf_statelim);
RBT_PROTOTYPE(pf_statelim_nm_tree, pf_statelim, pfstlim_nm_tree, cmp);
TAILQ_HEAD(pf_statelim_list, pf_statelim);
extern struct pf_statelim_id_tree pf_statelim_id_tree_active;
extern struct pf_statelim_list pf_statelim_list_active;
extern struct pf_statelim_id_tree pf_statelim_id_tree_inactive;
extern struct pf_statelim_nm_tree pf_statelim_nm_tree_inactive;
extern struct pf_statelim_list pf_statelim_list_inactive;
static inline unsigned int
pf_statelim_enter(struct pf_statelim *pfstlim)
{
return (pc_sprod_enter(&pfstlim->pfstlim_lock));
}
static inline void
pf_statelim_leave(struct pf_statelim *pfstlim, unsigned int gen)
{
pc_sprod_leave(&pfstlim->pfstlim_lock, gen);
}
/*
* Source address pools
*/
struct pf_sourcelim;
struct pf_source {
RBT_ENTRY(pf_source) pfsr_tree;
RBT_ENTRY(pf_source) pfsr_ioc_tree;
struct pf_sourcelim *pfsr_parent;
sa_family_t pfsr_af;
u_int16_t pfsr_rdomain;
struct pf_addr pfsr_addr;
/* run state */
unsigned int pfsr_inuse;
unsigned int pfsr_intable;
struct pf_state_link_list pfsr_states;
time_t pfsr_empty_ts;
TAILQ_ENTRY(pf_source) pfsr_empty_gc;
/* rate limiter */
uint64_t pfsr_rate_ts;
struct {
uint64_t admitted;
uint64_t hardlimited;
uint64_t ratelimited;
} pfsr_counters;
};
RBT_HEAD(pf_source_tree, pf_source);
RBT_PROTOTYPE(pf_source_tree, pf_source, pfsr_tree, cmp);
RBT_HEAD(pf_source_ioc_tree, pf_source);
RBT_PROTOTYPE(pf_source_ioc_tree, pf_source, pfsr_ioc_tree, cmp);
TAILQ_HEAD(pf_source_list, pf_source);
struct pf_sourcelim {
RBT_ENTRY(pf_sourcelim) pfsrlim_id_tree;
RBT_ENTRY(pf_sourcelim) pfsrlim_nm_tree;
TAILQ_ENTRY(pf_sourcelim) pfsrlim_list;
struct kstat *pfsrlim_ks;
uint32_t pfsrlim_id;
char pfsrlim_nm[PF_SOURCELIM_NAME_LEN];
unsigned int pfsrlim_disabled;
/* config */
unsigned int pfsrlim_entries;
unsigned int pfsrlim_limit;
unsigned int pfsrlim_ipv4_prefix;
unsigned int pfsrlim_ipv6_prefix;
struct {
unsigned int limit;
unsigned int seconds;
} pfsrlim_rate;
struct {
char name[PF_TABLE_NAME_SIZE];
unsigned int hwm;
unsigned int lwm;
struct pfr_ktable *table;
} pfsrlim_overload;
/* run state */
struct pc_lock pfsrlim_lock;
struct pf_addr pfsrlim_ipv4_mask;
struct pf_addr pfsrlim_ipv6_mask;
uint64_t pfsrlim_rate_token;
uint64_t pfsrlim_rate_bucket;
/* number of pf_sources */
unsigned int pfsrlim_nsources;
struct pf_source_tree pfsrlim_sources;
struct pf_source_ioc_tree pfsrlim_ioc_sources;
struct {
/* number of times pf_source was allocated */
uint64_t addrallocs;
/* state was rejected because the address limit was hit */
uint64_t addrlimited;
/* no memory to create address thing */
uint64_t addrnomem;
/* sum of pf_source inuse gauges */
uint64_t inuse;
/* sum of pf_source admitted counters */
uint64_t admitted;
/* sum of pf_source hardlimited counters */
uint64_t hardlimited;
/* sum of pf_source ratelimited counters */
uint64_t ratelimited;
} pfsrlim_counters;
};
RBT_HEAD(pf_sourcelim_id_tree, pf_sourcelim);
RBT_PROTOTYPE(pf_sourcelim_id_tree, pf_sourcelim, pfsrlim_id_tree, cmp);
RBT_HEAD(pf_sourcelim_nm_tree, pf_sourcelim);
RBT_PROTOTYPE(pf_sourcelim_nm_tree, pf_sourcelim, pfsrlim_nm_tree, cmp);
TAILQ_HEAD(pf_sourcelim_list, pf_sourcelim);
extern struct pf_sourcelim_id_tree pf_sourcelim_id_tree_active;
extern struct pf_sourcelim_list pf_sourcelim_list_active;
extern struct pf_sourcelim_id_tree pf_sourcelim_id_tree_inactive;
extern struct pf_sourcelim_nm_tree pf_sourcelim_nm_tree_inactive;
extern struct pf_sourcelim_list pf_sourcelim_list_inactive;
static inline unsigned int
pf_sourcelim_enter(struct pf_sourcelim *pfsrlim)
{
return (pc_sprod_enter(&pfsrlim->pfsrlim_lock));
}
static inline void
pf_sourcelim_leave(struct pf_sourcelim *pfsrlim, unsigned int gen)
{
pc_sprod_leave(&pfsrlim->pfsrlim_lock, gen);
}
/*
* pf internals
*/
extern struct rwlock pf_lock;
struct pf_pdesc {
struct {
int done;
uid_t uid;
gid_t gid;
pid_t pid;
} lookup;
u_int64_t tot_len; /* Make Mickey money */
struct pf_addr nsaddr; /* src address after NAT */
struct pf_addr ndaddr; /* dst address after NAT */
struct pfi_kif *kif; /* incoming interface */
struct mbuf *m; /* mbuf containing the packet */
struct pf_addr *src; /* src address */
struct pf_addr *dst; /* dst address */
u_int16_t *pcksum; /* proto cksum */
u_int16_t *sport;
u_int16_t *dport;
u_int16_t osport;
u_int16_t odport;
u_int16_t hash;
u_int16_t nsport; /* src port after NAT */
u_int16_t ndport; /* dst port after NAT */
u_int32_t off; /* protocol header offset */
u_int32_t hdrlen; /* protocol header length */
u_int32_t p_len; /* length of protocol payload */
u_int32_t extoff; /* extension header offset */
u_int32_t fragoff; /* fragment header offset */
u_int32_t jumbolen; /* length from v6 jumbo header */
u_int32_t badopts; /* v4 options or v6 routing headers */
#define PF_OPT_OTHER 0x0001
#define PF_OPT_JUMBO 0x0002
#define PF_OPT_ROUTER_ALERT 0x0004
u_int16_t rdomain; /* original routing domain */
u_int16_t virtual_proto;
#define PF_VPROTO_FRAGMENT 256
sa_family_t af;
sa_family_t naf;
u_int8_t proto;
u_int8_t tos;
u_int8_t ttl;
u_int8_t dir; /* direction */
u_int8_t sidx; /* key index for source */
u_int8_t didx; /* key index for destination */
u_int8_t destchg; /* flag set when destination changed */
u_int8_t pflog; /* flags for packet logging */
union {
struct tcphdr tcp;
struct udphdr udp;
struct icmp icmp;
#ifdef INET6
struct icmp6_hdr icmp6;
struct mld_hdr mld;
struct nd_neighbor_solicit nd_ns;
#endif /* INET6 */
} hdr;
};
struct pf_anchor_stackframe {
struct pf_ruleset *sf_rs;
struct pf_rule *sf_anchor;
union {
struct pf_rule *u_r;
struct pf_anchor_stackframe *u_stack_top;
} u;
struct pf_anchor *sf_child;
int sf_jump_target;
};
#define sf_r u.u_r
#define sf_stack_top u.u_stack_top
enum {
PF_NEXT_RULE,
PF_NEXT_CHILD
};
extern struct cpumem *pf_anchor_stack;
enum pf_trans_type {
PF_TRANS_NONE,
PF_TRANS_GETRULE,
PF_TRANS_MAX
};
struct pf_trans {
LIST_ENTRY(pf_trans) pft_entry;
uint32_t pft_unit; /* process id */
uint64_t pft_ticket;
enum pf_trans_type pft_type;
union {
struct {
u_int32_t gr_version;
struct pf_anchor *gr_anchor;
struct pf_rule *gr_rule;
} u_getrule;
} u;
};
#define pftgr_version u.u_getrule.gr_version
#define pftgr_anchor u.u_getrule.gr_anchor
#define pftgr_rule u.u_getrule.gr_rule
extern struct timeout pf_purge_states_to;
extern struct task pf_purge_task;
extern struct timeout pf_purge_to;
struct pf_state *pf_state_ref(struct pf_state *);
void pf_state_unref(struct pf_state *);
extern struct rwlock pf_lock;
extern struct rwlock pf_state_lock;
extern struct mutex pf_frag_mtx;
extern struct mutex pf_inp_mtx;
#define PF_LOCK() do { \
rw_enter_write(&pf_lock); \
} while (0)
#define PF_UNLOCK() do { \
PF_ASSERT_LOCKED(); \
rw_exit_write(&pf_lock); \
} while (0)
#define PF_ASSERT_LOCKED() do { \
if (rw_status(&pf_lock) != RW_WRITE) \
splassert_fail(RW_WRITE, \
rw_status(&pf_lock),__func__);\
} while (0)
#define PF_ASSERT_UNLOCKED() do { \
if (rw_status(&pf_lock) == RW_WRITE) \
splassert_fail(0, rw_status(&pf_lock), __func__);\
} while (0)
#define PF_STATE_ENTER_READ() do { \
rw_enter_read(&pf_state_lock); \
} while (0)
#define PF_STATE_EXIT_READ() do { \
rw_exit_read(&pf_state_lock); \
} while (0)
#define PF_STATE_ENTER_WRITE() do { \
rw_enter_write(&pf_state_lock); \
} while (0)
#define PF_STATE_EXIT_WRITE() do { \
PF_STATE_ASSERT_LOCKED(); \
rw_exit_write(&pf_state_lock); \
} while (0)
#define PF_STATE_ASSERT_LOCKED() do { \
if (rw_status(&pf_state_lock) != RW_WRITE)\
splassert_fail(RW_WRITE, \
rw_status(&pf_state_lock), __func__);\
} while (0)
#define PF_FRAG_LOCK() mtx_enter(&pf_frag_mtx)
#define PF_FRAG_UNLOCK() mtx_leave(&pf_frag_mtx)
/* for copies to/from network byte order */
void pf_state_peer_hton(const struct pf_state_peer *,
struct pfsync_state_peer *);
void pf_state_peer_ntoh(const struct pfsync_state_peer *,
struct pf_state_peer *);
u_int16_t pf_pkt_hash(sa_family_t, uint8_t,
const struct pf_addr *, const struct pf_addr *,
uint16_t, uint16_t);
void pf_status_init(void);
void pf_status_clear(void);
int pf_status_read(struct pf_status *);
#endif /* _KERNEL */
#endif /* _NET_PFVAR_PRIV_H_ */
+338
View File
@@ -0,0 +1,338 @@
/*
* PF-on-Linux: master compatibility header (pfk).
*
* Every ported OpenBSD file includes <pfk.h> INSTEAD of the original
* #include block. pfk.h pulls Linux headers first, then provides the
* OpenBSD-flavored types/APIs the PF code expects, so the ported logic
* stays line-proximate to upstream (ISC, (c) 2026 PF-on-Linux contributors;
* ported code: OpenBSD project, see LICENSE).
*/
#ifndef _PFK_H
#define _PFK_H
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/jiffies.h>
#include <linux/ktime.h>
#include <linux/timekeeping.h>
#include <linux/random.h>
#include <linux/prandom.h>
#include <linux/percpu.h>
#include <linux/preempt.h>
#include <linux/cpumask.h>
#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/icmpv6.h>
#include <linux/inetdevice.h>
#include <linux/if_addr.h>
#include <linux/neighbour.h>
#include <net/route.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <net/icmp.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/dst.h>
#include <net/neighbour.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/highuid.h>
#include <linux/atomic.h>
#include <linux/hashtable.h>
#include <linux/jhash.h>
#include <linux/byteorder/generic.h>
#include <linux/ratelimit.h>
/* ------------------------------------------------------------ basic types */
#ifndef u_int8_t
typedef __u8 u_int8_t;
#endif
#ifndef u_int16_t
typedef __u16 u_int16_t;
#endif
#ifndef u_int32_t
typedef __u32 u_int32_t;
#endif
#ifndef u_int64_t
typedef __u64 u_int64_t;
#endif
#ifndef u64
typedef __u64 u64;
#endif
#ifndef u_int
typedef unsigned int u_int;
#endif
#ifndef u_char
typedef unsigned char u_char;
#endif
/* caddr_t/time_t/timeval: kernel provides caddr_t; BSD time types below */
#ifndef u_short
typedef unsigned short u_short;
#endif
typedef __be16 pf_in_port_t;
typedef __be32 pf_in_addr_t;
/* uapi linux/in6.h already provides s6_addr/s6_addr16/s6_addr32 macros
* matching OpenBSD usage on the same union layout. */
/* roundup/MIN/MAX/rounddown/NULL/PTR_ALIGN are already provided by the
* Linux kernel headers — use those. BSD-only extras kept under unique names. */
#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1)))
#define howmany(x, y) (((x)+((y)-1))/(y))
#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
#define PFK_PTR_ALIGN(p) ((caddr_t)(((unsigned long)(p) + 3) & ~3UL))
#define P2ALIGN(x, y) ((x) & -(y))
/* OpenBSD rwlock name; the kernel has its own debug `struct rwlock`, so the
* BSD-visible struct is pfk_rwlock + alias macro (no further kernel headers
* are included after pfk.h, so the alias cannot leak). */
struct pfk_rwlock {
struct rw_semaphore sem;
const char *name;
int is_writer;
atomic_t readers;
};
#define rwlock pfk_rwlock
#define rwlock_s pfk_rwlock
/* OpenBSD ioctl encoding: OUR kernel-side and our Linux pfctl use EXACTLY
* these macros so _IOR/_IOW direction bits stay bit-compatible with
* OpenBSD (Linux asm/ioctl.h differs). Ported TUs must include NO further
* kernel headers after pfk.h (see porting-notes). */
#undef _IO
#undef _IOR
#undef _IOW
#undef _IOWR
#define PFKXIOC_NRBITS 8
#define PFKXIOC_TYPEBITS 8
#define PFKXIOC_SIZEBITS 13
#define PFKXIOC_DIRBITS 2
#define PFKXIOC_NRSHIFT 0
#define PFKXIOC_TYPESHIFT (PFKXIOC_NRSHIFT + PFKXIOC_NRBITS)
#define PFKXIOC_SIZESHIFT (PFKXIOC_TYPESHIFT + PFKXIOC_TYPEBITS)
#define PFKXIOC_DIRSHIFT (PFKXIOC_SIZESHIFT + PFKXIOC_SIZEBITS + 1)
#define PFKXIOC_NONE 0U
#define PFKXIOC_WRITE 1U /* OpenBSD IOC_IN (copyin) */
#define PFKXIOC_READ 2U /* OpenBSD IOC_OUT (copyout) */
#define PFKXIOC(dir,type,nr,size) \
(((dir) << PFKXIOC_DIRSHIFT) | ((type) << PFKXIOC_TYPESHIFT) | \
((nr) << PFKXIOC_NRSHIFT) | ((size) << PFKXIOC_SIZESHIFT))
#define _IO(t, n) PFKXIOC(PFKXIOC_NONE, (t), (n), 0)
#define _IOWR(t, n, s) PFKXIOC(PFKXIOC_WRITE|PFKXIOC_READ, (t), (n), sizeof(s))
#define _IOW(t, n, s) PFKXIOC(PFKXIOC_WRITE, (t), (n), sizeof(s))
#define _IOR(t, n, s) PFKXIOC(PFKXIOC_READ, (t), (n), sizeof(s))
#define PFKIOC_TYPE(nr) (((nr) >> PFKXIOC_TYPESHIFT) & ((1U<<PFKXIOC_TYPEBITS)-1))
#define PFKIOC_NR(nr) (((nr) >> PFKXIOC_NRSHIFT) & ((1U<<PFKXIOC_NRBITS)-1))
#define PFKIOC_DIR(nr) (((nr) >> PFKXIOC_DIRSHIFT) & ((1U<<PFKXIOC_DIRBITS)-1))
/* OpenBSD endian names htobe64/htole64/beXXXtoh and ntoh/hton are already
* provided by linux/byteorder/generic.h — do NOT redefine (Werror). */
/* pfvar.h pulls <net/route.h> → resolves to the kernel's net/route.h;
* BSD-only bits it expects must be provided here. */
#define RTLABEL_LEN 32
/* syslog levels (BSD numbering == Linux numbering for these) */
#define LOG_EMERG 0
#define LOG_ALERT 1
#define LOG_CRIT 2
#define LOG_ERR 3
#define LOG_WARNING 4
#define LOG_NOTICE 5
#define LOG_INFO 6
#define LOG_DEBUG 7
void pfk_log(int level, const char *fmt, ...);
#define log pfk_log
#define printf pfk_printk_compat
int pfk_printk_compat(const char *fmt, ...);
#define panic(x...) do { pr_emerg("pfk panic: " x); BUG(); } while (0)
/* time */
typedef long time_t;
struct timeval { long tv_sec; long tv_usec; }; /* BSD layout (uapi may clash) */
static inline __u64 pfk_time_sec(void) { return ktime_get_seconds(); }
static inline __u64 pfk_time_ms(void) { return ktime_get_ns() / 1000000ULL; }
struct pfk_timeval { __s64 tv_sec; __s64 tv_usec; };
static inline void pfk_getmicrotime(struct pfk_timeval *tv)
{
struct timespec64 ts;
ktime_get_real_ts64(&ts);
tv->tv_sec = ts.tv_sec;
tv->tv_usec = ts.tv_nsec / 1000;
}
static inline __s64 pfk_ntptime_delta(void) { return 0; } /* PFLINUX: ntpd adj not modeled */
/* MALLOC / pool */
#define M_TEMP 0x10000
#define M_PF 0x10001
#define M_DEVBUF 0x10002
#define M_IFADDR 0x10003
#define M_PFX 0x10004
#define M_TAG 0x10005
#define M_PFADDR 0x10006
#define M_PFRWP 0x10007
#define M_PFTOC 0x10008
#define M_PFRTABLE 0x10009
#define M_IFMADDR 0x1000a
#define M_PFXSRC 0x1000b
#define M_ZOMBIE 0x1000c
#define M_PCR 0x1000d
#define M_PRoute 0x1000e
#define M_NOWAIT 0x01
#define M_WAITOK 0x02
#define M_CANFAIL 0x04
#define M_ZERO 0x08
void *pfk_malloc(size_t sz, int flags);
void pfk_free(void *p);
#define malloc(sz, t, f) pfk_malloc((sz), (f))
#define free(p, t) pfk_free(p)
/*
* pools: struct pool backed by kmem_cache when size fixed (pool_init),
* lazily created on first get for simplicity of many small pools.
*/
struct pool {
struct kmem_cache *slab;
size_t p_size;
int p_flags; /* PR_WAITOK semantics via M_* on init */
unsigned long p_alloc;
unsigned long p_used;
unsigned long p_hardlimit;
struct list_head p_objects; /* for zeroed reuse semantics if needed */
};
#define PR_WAITOK 0x01
#define PR_NOWAIT 0x02
#define PR_ZERO 0x08
struct srcptr_static { const char *file; int line; };
#define SRCPOINT() (&(struct srcptr_static){__FILE__, __LINE__})
int pool_init(struct pool *pl, size_t size, int align, int ipl,
const char *use, void *p, int flags,
void (*ih)(void *, void *), void *arg, struct srcptr_static *sp);
void pool_destroy(struct pool *pl);
void *pool_get(struct pool *pl, int flags);
void pool_put(struct pool *pl, void *v);
void pool_sethardlimit(struct pool *pl, unsigned long lim, const char *msg, int msglevel);
/* timeout.h: OpenBSD embeds `struct timeout` in statics/globals → fixed layout */
#include "compat/sys/timeout.h"
void timeout_set(struct timeout *to, timeout_fn *fn, void *arg);
void timeout_set_micro(struct timeout *to, timeout_fn *fn, void *arg);
int timeout_add(struct timeout *to, long ms);
int timeout_add_sec(struct timeout *to, int secs);
int timeout_add_usec(struct timeout *to, int us);
int timeout_del(struct timeout *to);
void timeout_barrier(struct timeout *to, int flags);
void timeout_del_sync(struct timeout *to);
int timeout_pending(struct timeout *to);
int tsleep(void *p, int pr, const char *w, int timo); /* PFLINUX: control-path only */
#define wakeup pfk_wakeup
void pfk_wakeup(void *p);
/* refcnt.h */
#include "compat/sys/refcnt.h"
/* rnd / random */
static inline u_int32_t arc4random(void) { return get_random_u32(); }
static inline void arc4random_buf(void *b, size_t l) { get_random_bytes(b, l); }
static inline u_int32_t arc4random_uniform(u_int32_t n) { return get_random_u32_below(n); }
static inline u_int32_t rnd(void) { return get_random_u32(); }
static inline u_int32_t random(void) { return get_random_u32(); }
#define karc4random() get_random_u32()
#define karc4random_uniform(n) get_random_u32_below(n)
/* copyin/copyout */
#define copyin(u, k, l) (copy_from_user((k), (u), (l)) ? EFAULT : 0)
#define copyout(k, u, l) (copy_to_user((u), (k), (l)) ? EFAULT : 0)
/* assert-ish */
#define KASSERT(cond) WARN_ON(!(cond))
#define __arraycount(a) (sizeof(a) / sizeof((a)[0]))
#define __predictfalse(x) unlikely(x)
#define __predicttrue(x) likely(x)
#define __predict(x, y) ((y) ? likely(x) : unlikely(x))
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
/* NET_LOCK: OpenBSD global network rwlock. PF data path runs under NET_READ;
* ioctls take NET_LOCK (write). We map to a global rw_semaphore. */
void pfk_net_lock_init(void);
void pfk_net_lock(void); /* write */
void pfk_net_unlock(void);
void pfk_net_read_enter(void); /* read */
void pfk_net_read_release(void);
#define NET_LOCK() pfk_net_lock()
#define NET_UNLOCK() pfk_net_unlock()
#define NET_READ_ENTER() pfk_net_read_enter()
#define NET_READ_RELEASE() pfk_net_read_release()
void rw_init(struct rwlock_s *l, const char *name);
void rw_enter(struct rwlock_s *l, int mode);
void rw_exit(struct rwlock_s *l);
int rw_status(struct rwlock_s *l);
#define RW_READER 1
#define RW_WRITER 2
#define RW_NAPUTS 0
#define rw_assert(l, m) do { } while (0) /* PFLINUX: advisory */
/* BSD queue.h/tree.h/staged helpers — the Linux kernel's list.h/rbtree.h
* define a few identically-named macros; ported TUs never use Linux's
* list APIs via those names, so we clear and override. */
#undef LIST_HEAD
#undef LIST_HEAD_INIT
#undef RB_ROOT
#undef RB_CLEAR_NODE
#include "compat/sys/queue.h"
#include "compat/sys/tree.h"
#include "compat/sys/socket.h"
#include "compat/net/if_types.h"
#include "compat/net/if_var.h"
/* mbuf + BSD wire structs + pf ifnet registry */
#include "pfk_mbuf.h"
#include "pfk_net.h"
#include "pfk_if.h"
/* OpenBSD digest + toeplitz helpers (vendored into compat/crypto, compat/net) */
#include "compat/net/toeplitz.h"
#include "compat/crypto/siphash.h"
/* pf headers resolve via -I module/include */
#define NPFSYNC 0
#define NPFLOG 1
#define NPFLOW 0
#define NCARP 0
#define NPF 1
void pfk_mod_init_done(void);
#endif /* _PFK_H */
+13
View File
@@ -0,0 +1,13 @@
/* PFLINUX internal API (module-internal prototypes) */
#ifndef _PFK_API_H
#define _PFK_API_H
#include <pfk.h>
#include <net/pfvar.h>
long pfk_ioctl(struct file *f, unsigned int cmd, unsigned long addr);
int pfk_enable(int on);
void pfk_status(struct pf_status *s);
int pfk_hooks_register(void);
void pfk_hooks_unregister(void);
#endif
+102
View File
@@ -0,0 +1,102 @@
/*
* PF-on-Linux: ifnet/address registry — OpenBSD `struct ifnet`/`in_ifaddr`
* views over Linux net_device + in_ifaddr lists (ISC 2026).
*/
#ifndef _PFK_IF_H
#define _PFK_IF_H
struct pfk_ifaddr {
struct pfk_ifaddr *ifa_next;
struct pfk_ifnet *ifa_ifp;
int ifa_refcnt;
int ifa_flags; /* BSD IFA_* */
struct sockaddr_storage ifa_addr_storage; /* BSD-ish sockaddr */
struct sockaddr *ifa_addr; /* -> storage */
struct sockaddr *ifa_mask;
struct net_device *dev;
__be32 addr4;
struct in6_addr addr6;
int family; /* AF_INET/AF_INET6 */
int scope; /* link/site for v6 */
};
struct pfk_ifqueue; /* M5 */
struct pfk_ifnet {
char if_xname[IFNAMSIZ];
int if_index;
struct net_device *dev;
int if_flags; /* BSD-mapped IFF_* */
int if_xflags; /* BSD IFFX_* */
int if_type; /* IFT_* */
int if_mtu;
void *if_softc;
struct pfk_ifaddr *if_addrlist; /* refreshed snapshot */
struct pf_kif *if_pf_kif; /* pf_if glue */
struct pfk_ifqueue *if_snd; /* M5 */
void *if_pf_rtable; /* unused (rt tables NG) */
int if_rdomain; /* always 0 (NG), kept for ABI */
struct rcu_head rcu;
struct list_head link;
int alive;
};
#define if_output pfk_if_output_placeholder
struct pfk_ifnet *pfk_ifp_byindex(int idx); /* NULL if gone */
struct pfk_ifnet *pfk_ifp_byname(const char *name);
struct pfk_ifnet *pfk_ifp_bydev(struct net_device *dev);
int pfk_if_addrlist_refresh(struct pfk_ifnet *ifp); /* NET_LOCK held */
void pfk_if_free(struct pfk_ifnet *ifp);
/* BSD IFF_* bits (OpenBSD values) — distinct from Linux! */
#define PFIFF_UP 0x00000001
#define PFIFF_BROADCAST 0x00000002
#define PFIFF_DEBUG 0x00000004
#define PFIFF_LOOPBACK 0x00000008
#define PFIFF_POINTOPOINT 0x00000010
#define PFIFF_RUNNING 0x00000040
#define PFIFF_PROMISC 0x00000100
#define PFIFF_ALLMULTI 0x00000200
#define PFIFF_MULTICAST 0x00008000
#define PFIFF_RESOLVE 0x02000000
#define PFIFF_IPV4 0x10000000
#define PFIFF_IPV6 0x20000000
/* NOTE: BSD IFF_* bit values are PFIFF_*; staged port files are sed'ed
* IFF_* → PFIFF_* (IFF_ macros must NEVER alias linux netdev flags).
* BSD IFA_* */
#define IFA_BROADCAST_ 0x02
#define IFA_PRIMARY_ 0x04
#define IFA_SECONDARY_ 0x08
struct mbuf_list { struct mbuf *ml_first, *ml_last; int ml_len; };
/* egress interface (default-route dev), maintained on fib/net events */
struct pfk_ifnet *pfk_egress_if(void);
void pfk_egress_refresh(void);
int pfk_if_init(void);
void pfk_if_exit(void);
void pfk_if_refresh(struct pfk_ifnet *ifp);
struct pfk_ifnet *pfk_if_first(void);
struct pfk_ifnet *pfk_if_next(struct pfk_ifnet *ifp);
struct pfk_ifnet *pfk_if_next_from(int *idp);
struct net_device *ip_rt_get_default_dev(struct net *net);
/* xmit API used by pf_route/pf output (implemented in pfk_xmit.c) */
int if_output_tso(struct pfk_ifnet *ifp, struct mbuf **mp,
struct sockaddr *dst, void *rt, int mtu);
int if_output_ml(struct pfk_ifnet *ifp, struct mbuf_list *ml,
struct sockaddr *dst, void *rt);
int if_enqueue(struct pfk_ifnet *ifp, struct mbuf *m);
/* addr lookups (ifa_ifwithaddr, in_ifwithaddr etc.) */
struct pfk_ifaddr *pfk_ifwithaddr(const struct sockaddr *sa);
struct pfk_ifaddr *pfk_ifwithroute(int family, const struct sockaddr *dst,
const struct sockaddr *gate, struct pfk_ifnet **ifp_out);
/* mib-ish status for pfctl DIOCGIFSTATS */
struct pfk_if_data { unsigned long long ifi_ibytes, ifi_obytes; };
void pfk_if_stats(struct pfk_ifnet *ifp, struct pfk_if_data *out);
#endif /* _PFK_IF_H */
+166
View File
@@ -0,0 +1,166 @@
/*
* PF-on-Linux mbuf shim: OpenBSD `struct mbuf` over Linux `sk_buff`.
*
* Design (see spec §4.1): PF-facing mbufs are ALWAYS single-segment
* (linearized on ingress). `m_data`/`m_len` mirror `skb->data`/`skb->len`.
* `m_pkthdr` carries PF's per-packet metadata (pf.* bits, ph.* aliases).
* Chains (m_next) are used only by our own concatenation (m_cat → copy);
* upstream PF never builds multi-segment chains it would hand back to Linux.
*
* (c) 2026 PF-on-Linux contributors — ISC.
*/
#ifndef _PFK_MBUF_H
#define _PFK_MBUF_H
#include <linux/skbuff.h>
struct pfk_ifnet; /* forward (pfk_if.h) */
struct pf_state_key;
struct inpcb;
struct pf_tag;
struct m_tag {
struct m_tag *m_tag_next;
int m_tag_type;
u_int m_tag_len; /* opaque: byte count of data[] */
u_char m_tag_data[];
};
/* mbuf types (OpenBSD numbering) */
#define MT_FREE 0
#define MT_DATA 1
#define MT_HEADER 2
#define MT_SONAME 3
#define MT_SBUF 4
#define MT_ZOMBIE 5
#define MT_USER 6
#define MT_RTABLE 7
#define MT_IFADDR 8
#define MT_EXT 9
#define MT_RTMSG 10
#define MT_SOCKET 11
#define MT_PFDESC 12
#define MT_TAG 13
#define MT_OFDESC 14
#define MT_TAGV 10
#define MT_PFTOC TAG_PF
#define MT_PF TAG_PF
#define TAG_PF 0x50460000
#define TAG_PF_RR (TAG_PF + 1)
#define MT_PFTOC TAG_PF
struct pkthdr_pf {
u_int flags;
struct pf_state_key *statekey;
struct inpcb *inp;
u_int32_t qid;
int16_t prio;
u_int8_t delay;
u_int8_t routed;
u_int8_t dir;
u_int8_t reason;
u_int16_t ruleset;
struct pfk_tag *tag;
};
struct pkthdr {
int len;
struct pkthdr_pf pf;
u_int csum_flags;
void *ph_cookie;
u_int32_t ph_flowid;
u_int ph_ifidx;
u_int ph_rtableid;
struct pfk_timeval ph_timestamp;
struct pfk_ifnet *ifp;
struct pfk_ifnet *rcvif;
u_short ph; /* tso segs: unused, kept as pad */
u_int8_t af;
u_int16_t proto;
u_int hdr_len;
struct m_tag *tags;
int pkthdr_len; /* == len mirror */
};
#define M_EXT 0x0001
#define M_PKTHDR 0x0002
#define M_EOR 0x0004
#define M_RO 0x0010
#define M_BCAST 0x0020
#define M_MCAST 0x0040
#define M_LOOP 0x0080
#define M_SKIP_FIREWALL 0x0100
#define M_BPF_MCAST 0x0200
#define M_PROMISC 0x0400
#define M_READONLY 0x0800
#define M_CANTFIND (M_READONLY)
#define M_DONTFRAG 0x1000
struct mbuf {
struct mbuf *m_next;
struct mbuf *m_nextout;
u_short m_flags;
u_short m_len;
caddr_t m_data;
u_short m_type;
u_short m_maxsize;
int m_refcnt;
struct sk_buff *skb; /* canonical storage (linear) */
struct pkthdr m_pkthdr; /* valid iff M_PKTHDR */
};
#define MGET(m, f, t) do { (m) = m_get((f), (t)); } while (0)
#define MGETHDR(m, f, t) do { (m) = m_gethdr((f), (t)); } while (0)
#define mtod(m, t) ((t)((m)->m_data))
#define MTOU(m, t) ((t)((m)->m_data))
#define MFREE(m, n) ((n) = m_free((m)))
/* lifecycle */
struct mbuf *m_get(int how, short type);
struct mbuf *m_gethdr(int how, short type);
struct mbuf *m_alloc_skb(struct sk_buff *skb, int how); /* wrap borrowed skb */
struct mbuf *m_devget(char *buf, int totlen, int off,
struct pfk_ifnet *ifp, void (*copyin_fc)(caddr_t, int));
void pfk_m_setpkthdr(struct mbuf *m);
struct mbuf *m_copym(struct mbuf *m, int off, int len, int wait);
struct mbuf *m_dup(struct mbuf *m, int wait); /* full dup + headroom */
#define m_copypacket(m, w) m_copym((m), 0, 0, (w))
void m_adj(struct mbuf *m, int dlen);
void m_trim(struct mbuf *m, int dlen);
int m_cat(struct mbuf *to, struct mbuf *from); /* copies+consumes from */
caddr_t m_copyback(struct mbuf *m, int off, int len, const void *copied);
void m_copydata(const struct mbuf *m, int off, int len, caddr_t dest);
caddr_t m_getptr(struct mbuf *m, int loc, int *off);
int m_clump(struct mbuf **m0p, int len, int *mp_off, int *mp_len, caddr_t *doff);
void m_free_ext(struct mbuf *m);
struct mbuf *m_free(struct mbuf *m); /* returns next */
void m_freem(struct mbuf *m);
struct mbuf *m_dtom(struct sk_buff *skb); /* reverse map via skb->cb */
static inline struct sk_buff *m_to_skb(struct mbuf *m) { return m->skb; }
/* linearize: PF ingress guarantee */
int pfk_mbuf_linearize(struct mbuf *m); /* pskb_expand if fragged */
void pfk_mbuf_refresh(struct mbuf *m); /* resync m_len/pkthdr from skb */
/* m_tag */
struct m_tag *m_tag_alloc(int type, int len, int wait, caddr_t *align_data);
void m_tag_free(struct m_tag *m);
void m_tag_prepend(struct mbuf *m, struct m_tag *tag);
void m_tag_prepend_packet(struct mbuf *m, struct m_tag *tag);
void m_tag_delete(struct mbuf *m, struct m_tag *tag);
struct m_tag *m_tag_find(struct mbuf *m, int type, struct m_tag *start);
struct m_tag *m_tag_copy(struct m_tag *tag, int how);
int m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how);
void m_tag_delete_chain(struct mbuf *m, struct m_tag *end);
struct m_tag *m_tag_first(struct mbuf *m);
struct m_tag *m_tag_next(struct mbuf *m, struct m_tag *tag);
void m_tag_attach(struct mbuf *m, struct m_tag *t); /* append order */
/* PF flowid/toeplitz ingress hook + sysctl-ish knobs */
int pfk_mbuf_init(void);
void pfk_mbuf_exit(void);
#endif /* _PFK_MBUF_H */
+190
View File
@@ -0,0 +1,190 @@
/*
* PF-on-Linux BSD wire-protocol structs + checksum helpers (ISC 2026).
* Field names match OpenBSD headers; staging seds rename `struct ip` etc.
* to the pf_* names defined here so they never collide with Linux uapi.
* Byte layouts below are the little-endian variants (x86/arm64); the
* bitfield orderings replicate OpenBSD netinet headers exactly.
*/
#ifndef _PFK_NET_H
#define _PFK_NET_H
/* ---- IPv4 header (OpenBSD <netinet/ip.h> layout, LE bitfield order) ---- */
struct pf_ip {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ip_hl:4, ip_v:4;
#else
__u8 ip_v:4, ip_hl:4;
#endif
__u8 ip_tos;
__be16 ip_len;
__be16 ip_id;
__be16 ip_off;
#define IP_RF 0x8000
#define IP_OFFLP 0x3fff
__u8 ip_ttl;
__u8 ip_p;
__be16 ip_sum;
struct in_addr ip_src, ip_dst;
};
#define IP_MAXPACKET 65535
#define IP_DEFAULT_TTL 64
#define IPV4_TTL 64
/* ---- TCP (OpenBSD <netinet/tcp.h> names) ---- */
struct pf_tcphdr {
__be16 th_sport, th_dport;
__be32 th_seq, th_ack;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 th_x2:4, th_off:4;
#else
__u8 th_off:4, th_x2:4;
#endif
__u8 th_flags;
__be16 th_win;
__be16 th_sum;
__be16 th_urp;
};
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
/* tcp_fsm.h states (same numeric as Linux TCP_* enum) */
#define TCPS_CLOSED 0
#define TCPS_LISTEN 1
#define TCPS_SYN_SENT 2
#define TCPS_SYN_RECEIVED 3
#define TCPS_ESTABLISHED 4
#define TCPS_CLOSE_WAIT 5
#define TCPS_FIN_WAIT_1 6
#define TCPS_CLOSING 7
#define TCPS_LAST_ACK 8
#define TCPS_FIN_WAIT_2 9
#define TCPS_TIME_WAIT 10
/* ---- UDP ---- */
struct pf_udphdr {
__be16 uh_sport, uh_dport;
__be16 uh_ulen;
__be16 uh_sum;
};
/* ---- ICMP (OpenBSD <netinet/ip_icmp.h> names/values) ---- */
struct pf_icmp {
__u8 icmp_type;
__u8 icmp_code;
__be16 icmp_cksum;
union {
__be16 ih_id[2]; /* id, seq */
struct { __u8 type, code; __be16 cksum; } ih_type_hdr;
__be32 ih_gwaddr;
struct ih_frags { __be16 ih_rrechk; __be16 ih_length; } ih_frag;
} icmp_hun;
#define icmp_id icmp_hun.ih_id[0]
#define icmp_seq icmp_hun.ih_id[1]
#define icmp_cksum_alt icmp_hun.ih_type_hdr.cksum
#define icmp_gwaddr icmp_hun.ih_gwaddr
union {
__s8 id_pad[8];
__be16 id_ipid[2];
struct pf_ip id_ip;
struct ih_pmtu { __be16 reserved; __be16 mtu; } ih_pmtu;
struct ih_rtradv { __u8 irt_num_addrs, irt_wpa;
__be16 lifetime; } ih_rtradv;
} icmp_data;
#define icmp_rip icmp_data.id_ip
#define icmp_ppsmtu icmp_data.ih_pmtu.mtu
};
#define ICMP_ECHOREPLY 0
#define ICMP_UNREACH 3
#define ICMP_UNREACH_NET 0
#define ICMP_UNREACH_HOST 1
#define ICMP_UNREACH_PROTOCOL 2
#define ICMP_UNREACH_PORT 3
#define ICMP_UNREACH_NEEDFRAG 4
#define ICMP_UNREACH_SRCFAIL 5
#define ICMP_UNREACH_NET_UNKNOWN 6
#define ICMP_UNREACH_HOST_UNKNOWN 7
#define ICMP_UNREACH_ISOLATED 8
#define ICMP_UNREACH_NET_PROHIB 9
#define ICMP_UNREACH_HOST_PROHIB 10
#define ICMP_UNREACH_TOSNET 11
#define ICMP_UNREACH_TOSHOST 12
#define ICMP_UNREACH_FILTER_PROHIB 13
#define ICMP_UNREACH_HOST_PRECEDENCE 14
#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15
#define ICMP_SOURCEQUENCH 4
#define ICMP_REDIRECT 5
#define ICMP_ALTHOSTADDR 6
#define ICMP_ECHO 8
#define ICMP_ROUTERADVERT 9
#define ICMP_ROUTERSOLICIT 10
#define ICMP_TIMXCEED 11
#define ICMP_TIMXCEED_INTRANS 0
#define ICMP_TIMXCEED_REASS 1
#define ICMP_PARAMPROB 12
#define ICMP_TSTAMP 13
#define ICMP_TSTAMPREPLY 14
#define ICMP_INFO_REQUEST 15
#define ICMP_INFO_REPLY 16
#define ICMP_ADDRESS 17
#define ICMP_ADDRESSREPLY 18
#define ICMP_MAXTYPE 18
/* ---- IPv6 (OpenBSD <netinet/ip6.h> ctl-union + macros) ---- */
struct pf_ip6_hdr {
union {
struct ip6_hdrctl {
__u32 ip6_un1_flow;
__be16 ip6_un1_plen;
__u8 ip6_un1_nxt;
__u8 ip6_un1_hlim;
} ip6_un1;
} ip6_ctlun;
struct in6_addr ip6_src;
struct in6_addr ip6_dst;
};
#define ip6_flow ip6_ctlun.ip6_un1->ip6_un1_flow
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
/* NOTE ip6_flow above is a pointer trick in OpenBSD; PF reads/writes
* it via explicit helpers only — provide the plain accessor instead: */
#undef ip6_flow
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
#define IPV6_VERSION 0x60
#define IPV6_VERSION_MASK 0xf0
#define v_hl i_vhl
#define traffic_class i_tc1, i_tc2
/* flow macros (OpenBSD) */
static inline __u32 PF6_FLOWlabel(const struct pf_ip6_hdr *h)
{ return be32_to_cpu(h->ip6_flow) & 0x000fffff; }
static inline __u8 PF6_VERSION(const struct pf_ip6_hdr *h)
{ return be32_to_cpu(h->ip6_flow) >> 28; }
static inline __u8 PF6_CLASS(const struct pf_ip6_hdr *h)
{ return (be32_to_cpu(h->ip6_flow) >> 20) & 0xff; }
/* ---- ICMPv6: PF code's field names (icmp6_type/code/cksum/identifier/
* sequence/mtu) are provided by Linux's own <linux/icmpv6.h> struct
* icmp6hdr + its member macros; staging seds `struct icmp6_hdr` →
* `struct icmp6hdr` (see stage-port.sh). No private definition needed. */
/* BSD IPPROTO_ / IP levels (identical numerics to Linux; aliases kept) */
#define IPPROTO_MAX_ IPPROTO_MAX
/* ---- checksum helpers (ported in_cksum etc.) ---- */
u_int16_t pfk_in_cksum(const void *data, int len); /* one's complement sum */
__sum16 pfk_icmp6_cksum(const struct pf_ip6_hdr *ip6,
const struct icmp6hdr *ic6, int len);
void pfk_send_icmp_error(int family, struct sk_buff *skb_in, int type,
int code, __be32 info);
#endif /* _PFK_NET_H */