aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib
diff options
context:
space:
mode:
authorMax Laier <mlaier@FreeBSD.org>2004-02-26 02:34:12 +0000
committerMax Laier <mlaier@FreeBSD.org>2004-02-26 02:34:12 +0000
commit2bbe8ffc9d0ed0a0795c6e4af4b11f4c7be49421 (patch)
tree93a5df3113f8f9cf3fd0b519d7ad89db6831f1fc /sys/contrib
parent3ef891af51c7b93236727ba7aa6e2490f1cc8158 (diff)
downloadsrc-2bbe8ffc9d0ed0a0795c6e4af4b11f4c7be49421.tar.gz
src-2bbe8ffc9d0ed0a0795c6e4af4b11f4c7be49421.zip
Bring diff from the security/pf port. This has code been tested as a port
for a long time and is run in production use. This is the code present in portversion 2.03 with some additional tweaks. The rather extensive diff accounts for: - locking (to enable pf to work with a giant-free netstack) - byte order difference between OpenBSD and FreeBSD for ip_len/ip_off - conversion from pool(9) to zone(9) - api differences etc. Approved by: bms(mentor) (in general)
Notes
Notes: svn path=/head/; revision=126261
Diffstat (limited to 'sys/contrib')
-rw-r--r--sys/contrib/pf/net/if_pflog.c165
-rw-r--r--sys/contrib/pf/net/if_pflog.h4
-rw-r--r--sys/contrib/pf/net/if_pfsync.c199
-rw-r--r--sys/contrib/pf/net/if_pfsync.h8
-rw-r--r--sys/contrib/pf/net/pf.c870
-rw-r--r--sys/contrib/pf/net/pf_ioctl.c1140
-rw-r--r--sys/contrib/pf/net/pf_norm.c187
-rw-r--r--sys/contrib/pf/net/pf_osfp.c45
-rw-r--r--sys/contrib/pf/net/pf_table.c328
-rw-r--r--sys/contrib/pf/net/pfvar.h141
-rw-r--r--sys/contrib/pf/netinet/in4_cksum.c168
11 files changed, 3205 insertions, 50 deletions
diff --git a/sys/contrib/pf/net/if_pflog.c b/sys/contrib/pf/net/if_pflog.c
index e856f2cc965f..791159710beb 100644
--- a/sys/contrib/pf/net/if_pflog.c
+++ b/sys/contrib/pf/net/if_pflog.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: if_pflog.c,v 1.9 2003/05/14 08:42:00 canacar Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -33,14 +34,32 @@
* PURPOSE.
*/
+#if defined(__FreeBSD__)
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
+#if !defined(__FreeBSD__)
#include "bpfilter.h"
#include "pflog.h"
+#elif __FreeBSD__ >= 5
+#include "opt_bpf.h"
+#define NBPFILTER DEV_BPF
+#include "opt_pf.h"
+#define NPFLOG DEV_PFLOG
+#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
+#if defined(__FreeBSD__)
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/sockio.h>
+#else
#include <sys/ioctl.h>
+#endif
#include <net/if.h>
#include <net/if_types.h>
@@ -54,6 +73,10 @@
#include <netinet/ip.h>
#endif
+#if defined(__FreeBSD__)
+#include <machine/in_cksum.h>
+#endif
+
#ifdef INET6
#ifndef INET
#include <netinet/in.h>
@@ -64,6 +87,10 @@
#include <net/pfvar.h>
#include <net/if_pflog.h>
+#if defined(__FreeBSD__)
+#define PFLOGNAME "pflog"
+#endif
+
#define PFLOGMTU (32768 + MHLEN + MLEN)
#ifdef PFLOGDEBUG
@@ -72,17 +99,89 @@
#define DPRINTF(x)
#endif
+#if !defined(__FreeBSD__)
struct pflog_softc pflogif[NPFLOG];
+#endif
+#if defined(__FreeBSD__)
+void pflog_clone_destroy(struct ifnet *);
+int pflog_clone_create(struct if_clone *, int);
+#else
void pflogattach(int);
+#endif
int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
int pflogioctl(struct ifnet *, u_long, caddr_t);
void pflogrtrequest(int, struct rtentry *, struct sockaddr *);
void pflogstart(struct ifnet *);
+#if !defined(__FreeBSD__)
extern int ifqmaxlen;
+#endif
+
+#if defined(__FreeBSD__)
+static MALLOC_DEFINE(M_PFLOG, PFLOGNAME, "Packet Filter Logging Interface");
+static LIST_HEAD(pflog_list, pflog_softc) pflog_list;
+struct if_clone pflog_cloner = IF_CLONE_INITIALIZER(PFLOGNAME,
+ pflog_clone_create, pflog_clone_destroy, 1, IF_MAXUNIT);
+
+void
+pflog_clone_destroy(struct ifnet *ifp)
+{
+ struct pflog_softc *sc;
+
+ sc = ifp->if_softc;
+
+ /*
+ * Does we really need this?
+ */
+ IF_DRAIN(&ifp->if_snd);
+
+ bpfdetach(ifp);
+ if_detach(ifp);
+ LIST_REMOVE(sc, sc_next);
+ free(sc, M_PFLOG);
+}
+#endif /* __FreeBSD__ */
+
+#if defined(__FreeBSD__)
+int
+pflog_clone_create(struct if_clone *ifc, int unit)
+{
+ struct pflog_softc *sc;
+
+ MALLOC(sc, struct pflog_softc *, sizeof(*sc), M_PFLOG, M_WAITOK|M_ZERO);
+
+#if (__FreeBSD_version < 501113)
+ sc->sc_if.if_name = PFLOGNAME;
+ sc->sc_if.if_unit = unit;
+#else
+ if_initname(&sc->sc_if, ifc->ifc_name, unit);
+#endif
+ sc->sc_if.if_mtu = PFLOGMTU;
+ sc->sc_if.if_ioctl = pflogioctl;
+ sc->sc_if.if_output = pflogoutput;
+ sc->sc_if.if_start = pflogstart;
+ sc->sc_if.if_type = IFT_PFLOG;
+ sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
+ sc->sc_if.if_hdrlen = PFLOG_HDRLEN;
+ sc->sc_if.if_softc = sc;
+ /*
+ * We would get a message like
+ * "in6_ifattach: pflog0 is not multicast capable, IPv6 not enabled".
+ * We need a patch to in6_ifattach() to exclude interface type
+ * IFT_PFLOG.
+ */
+ if_attach(&sc->sc_if);
+
+ LIST_INSERT_HEAD(&pflog_list, sc, sc_next);
+#if NBPFILTER > 0
+ bpfattach(&sc->sc_if, DLT_PFLOG, PFLOG_HDRLEN);
+#endif
+ return (0);
+}
+#else /* !__FreeBSD__ */
void
pflogattach(int npflog)
{
@@ -111,6 +210,7 @@ pflogattach(int npflog)
#endif
}
}
+#endif /* __FreeBSD__ */
/*
* Start output on the pflog interface.
@@ -119,14 +219,28 @@ void
pflogstart(struct ifnet *ifp)
{
struct mbuf *m;
+#if defined(__FreeBSD__) && defined(ALTQ)
+ struct ifaltq *ifq;
+#else
+ struct ifqueue *ifq;
+#endif
int s;
+#if defined(__FreeBSD__)
+ ifq = &ifp->if_snd;
+#endif
for (;;) {
s = splimp();
+#if defined(__FreeBSD__)
+ IF_LOCK(ifq);
+ _IF_DROP(ifq);
+ _IF_DEQUEUE(ifq, m);
+ IF_UNLOCK(ifq);
+#else
IF_DROP(&ifp->if_snd);
IF_DEQUEUE(&ifp->if_snd, m);
+#endif
splx(s);
-
if (m == NULL)
return;
else
@@ -188,7 +302,11 @@ pflog_packet(struct ifnet *ifp, struct mbuf *m, sa_family_t af, u_int8_t dir,
hdr.af = af;
hdr.action = rm->action;
hdr.reason = reason;
+#if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
+ snprintf(hdr.ifname, IFNAMSIZ, "%s%d", ifp->if_name, ifp->if_unit);
+#else
memcpy(hdr.ifname, ifp->if_xname, sizeof(hdr.ifname));
+#endif
if (am == NULL) {
hdr.rulenr = htonl(rm->nr);
@@ -221,7 +339,12 @@ pflog_packet(struct ifnet *ifp, struct mbuf *m, sa_family_t af, u_int8_t dir,
m1.m_len = PFLOG_HDRLEN;
m1.m_data = (char *) &hdr;
+#if defined(__FreeBSD__)
+ KASSERT((!LIST_EMPTY(&pflog_list)), ("pflog: no interface"));
+ ifn = &LIST_FIRST(&pflog_list)->sc_if;
+#else
ifn = &(pflogif[0].sc_if);
+#endif
if (ifn->if_bpf)
bpf_mtap(ifn->if_bpf, &m1);
@@ -229,3 +352,43 @@ pflog_packet(struct ifnet *ifp, struct mbuf *m, sa_family_t af, u_int8_t dir,
return (0);
}
+
+#if defined(__FreeBSD__)
+static int
+pflog_modevent(module_t mod, int type, void *data)
+{
+ int error = 0;
+
+ switch (type) {
+ case MOD_LOAD:
+ LIST_INIT(&pflog_list);
+ if_clone_attach(&pflog_cloner);
+ printf("pflog: $Name: $\n");
+ break;
+
+ case MOD_UNLOAD:
+ if_clone_detach(&pflog_cloner);
+ while (!LIST_EMPTY(&pflog_list))
+ pflog_clone_destroy(
+ &LIST_FIRST(&pflog_list)->sc_if);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+static moduledata_t pflog_mod = {
+ "pflog",
+ pflog_modevent,
+ 0
+};
+
+#define PFLOG_MODVER 1
+
+DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+MODULE_VERSION(pflog, PFLOG_MODVER);
+#endif /* __FreeBSD__ */
diff --git a/sys/contrib/pf/net/if_pflog.h b/sys/contrib/pf/net/if_pflog.h
index 9333f48eebf7..22a85eaee3e9 100644
--- a/sys/contrib/pf/net/if_pflog.h
+++ b/sys/contrib/pf/net/if_pflog.h
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: if_pflog.h,v 1.9 2003/07/15 20:27:27 dhartmei Exp $ */
/*
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
@@ -29,6 +30,9 @@
struct pflog_softc {
struct ifnet sc_if; /* the interface */
+#if defined(__FreeBSD__)
+ LIST_ENTRY(pflog_softc) sc_next;
+#endif
};
/* XXX keep in sync with pfvar.h */
diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c
index e29a06ec8615..8448266f001b 100644
--- a/sys/contrib/pf/net/if_pfsync.c
+++ b/sys/contrib/pf/net/if_pfsync.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: if_pfsync.c,v 1.6 2003/06/21 09:07:01 djm Exp $ */
/*
@@ -26,16 +27,34 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if defined(__FreeBSD__) && __FreeBSD__ >= 5
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
+#if !defined(__FreeBSD__)
#include "bpfilter.h"
#include "pfsync.h"
+#elif __FreeBSD__ >= 5
+#include "opt_bpf.h"
+#define NBPFILTER DEV_BPF
+#include "opt_pf.h"
+#define NPFSYNC DEV_PFSYNC
+#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
+#if defined(__FreeBSD__)
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/sockio.h>
+#else
#include <sys/ioctl.h>
#include <sys/timeout.h>
+#endif
#include <net/if.h>
#include <net/if_types.h>
@@ -57,6 +76,10 @@
#include <net/pfvar.h>
#include <net/if_pfsync.h>
+#if defined(__FreeBSD__)
+#define PFSYNCNAME "pfsync"
+#endif
+
#define PFSYNC_MINMTU \
(sizeof(struct pfsync_header) + sizeof(struct pf_state))
@@ -67,9 +90,16 @@ int pfsyncdebug;
#define DPRINTF(x)
#endif
+#if !defined(__FreeBSD__)
struct pfsync_softc pfsyncif;
+#endif
+#if defined(__FreeBSD__)
+void pfsync_clone_destroy(struct ifnet *);
+int pfsync_clone_create(struct if_clone *, int);
+#else
void pfsyncattach(int);
+#endif
void pfsync_setmtu(struct pfsync_softc *sc, int);
int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
@@ -80,9 +110,80 @@ struct mbuf *pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action);
int pfsync_sendout(struct pfsync_softc *sc);
void pfsync_timeout(void *v);
+#if !defined(__FreeBSD__)
extern int ifqmaxlen;
+#endif
+
+#if defined(__FreeBSD__)
+static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
+static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
+struct if_clone pfsync_cloner = IF_CLONE_INITIALIZER(PFSYNCNAME,
+ pfsync_clone_create, pfsync_clone_destroy, 1, IF_MAXUNIT);
void
+pfsync_clone_destroy(struct ifnet *ifp)
+{
+ struct pfsync_softc *sc;
+
+ sc = ifp->if_softc;
+ callout_stop(&sc->sc_tmo);
+
+ /*
+ * Does we really need this?
+ */
+ IF_DRAIN(&ifp->if_snd);
+
+#if NBPFILTER > 0
+ bpfdetach(ifp);
+#endif
+ if_detach(ifp);
+ LIST_REMOVE(sc, sc_next);
+ free(sc, M_PFSYNC);
+}
+#endif /* __FreeBSD__ */
+
+#if defined(__FreeBSD__)
+int
+pfsync_clone_create(struct if_clone *ifc, int unit)
+{
+ struct pfsync_softc *sc;
+
+ MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
+ M_WAITOK|M_ZERO);
+
+ sc->sc_count = 8;
+#if (__FreeBSD_version < 501113)
+ sc->sc_if.if_name = PFSYNCNAME;
+ sc->sc_if.if_unit = unit;
+#else
+ if_initname(&sc->sc_if, ifc->ifc_name, unit);
+#endif
+ sc->sc_if.if_ioctl = pfsyncioctl;
+ sc->sc_if.if_output = pfsyncoutput;
+ sc->sc_if.if_start = pfsyncstart;
+ sc->sc_if.if_type = IFT_PFSYNC;
+ sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
+ sc->sc_if.if_hdrlen = PFSYNC_HDRLEN;
+ sc->sc_if.if_baudrate = IF_Mbps(100);
+ sc->sc_if.if_softc = sc;
+ pfsync_setmtu(sc, MCLBYTES);
+ /*
+ * XXX
+ * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE
+ * if Gaint lock is removed from the network stack.
+ */
+ callout_init(&sc->sc_tmo, 0);
+ if_attach(&sc->sc_if);
+
+ LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
+#if NBPFILTER > 0
+ bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN);
+#endif
+
+ return (0);
+}
+#else /* !__FreeBSD__ */
+void
pfsyncattach(int npfsync)
{
struct ifnet *ifp;
@@ -109,6 +210,7 @@ pfsyncattach(int npfsync)
bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
#endif
}
+#endif
/*
* Start output on the pfsync interface.
@@ -117,12 +219,27 @@ void
pfsyncstart(struct ifnet *ifp)
{
struct mbuf *m;
+#if defined(__FreeBSD__) && defined(ALTQ)
+ struct ifaltq *ifq;
+#else
+ struct ifqueue *ifq;
+#endif
int s;
+#if defined(__FreeBSD__)
+ ifq = &ifp->if_snd;
+#endif
for (;;) {
s = splimp();
+#if defined(__FreeBSD__)
+ IF_LOCK(ifq);
+ _IF_DROP(ifq);
+ _IF_DEQUEUE(ifq, m);
+ IF_UNLOCK(ifq);
+#else
IF_DROP(&ifp->if_snd);
IF_DEQUEUE(&ifp->if_snd, m);
+#endif
splx(s);
if (m == NULL)
@@ -192,7 +309,9 @@ pfsync_get_mbuf(sc, action)
struct pfsync_softc *sc;
u_int8_t action;
{
+#if !defined(__FreeBSD__)
extern int hz;
+#endif
struct pfsync_header *h;
struct mbuf *m;
int len;
@@ -223,19 +342,32 @@ pfsync_get_mbuf(sc, action)
sc->sc_mbuf = m;
sc->sc_ptr = (struct pf_state *)((char *)h + PFSYNC_HDRLEN);
+#if defined(__FreeBSD__)
+ callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
+ LIST_FIRST(&pfsync_list));
+#else
timeout_add(&sc->sc_tmo, hz);
+#endif
return (m);
}
+/*
+ * XXX: This function should be called with PF_LOCK held as it references
+ * pf_state.
+ */
int
pfsync_pack_state(action, st)
u_int8_t action;
struct pf_state *st;
{
+#if defined(__FreeBSD__)
+ struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
+#else
extern struct timeval time;
struct ifnet *ifp = &pfsyncif.sc_if;
struct pfsync_softc *sc = ifp->if_softc;
+#endif
struct pfsync_header *h;
struct pf_state *sp;
struct pf_rule *r = st->rule.ptr;
@@ -246,6 +378,16 @@ pfsync_pack_state(action, st)
if (action >= PFSYNC_ACT_MAX)
return (EINVAL);
+#if defined(__FreeBSD__)
+ /*
+ * XXX
+ * If we need to check mutex owned, PF_LOCK should be
+ * declared in pflog.ko. :-(
+ *
+ * PF_LOCK_ASSERT();
+ */
+ KASSERT((!LIST_EMPTY(&pfsync_list)), ("pfsync: no interface"));
+#endif
s = splnet();
m = sc->sc_mbuf;
if (m == NULL) {
@@ -278,7 +420,11 @@ pfsync_pack_state(action, st)
pf_state_peer_hton(&st->dst, &sp->dst);
bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
+#if defined(__FreeBSD__)
+ secs = time_second;
+#else
secs = time.tv_sec;
+#endif
sp->creation = htonl(secs - st->creation);
if (st->expire <= secs)
sp->expire = htonl(0);
@@ -310,8 +456,12 @@ int
pfsync_clear_state(st)
struct pf_state *st;
{
+#if defined(__FreeBSD__)
+ struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
+#else
struct ifnet *ifp = &pfsyncif.sc_if;
struct pfsync_softc *sc = ifp->if_softc;
+#endif
struct mbuf *m = sc->sc_mbuf;
int s, ret;
@@ -332,6 +482,7 @@ pfsync_timeout(void *v)
struct pfsync_softc *sc = v;
int s;
+ /* We don't need PF_LOCK/PF_UNLOCK here! */
s = splnet();
pfsync_sendout(sc);
splx(s);
@@ -344,10 +495,17 @@ pfsync_sendout(sc)
struct ifnet *ifp = &sc->sc_if;
struct mbuf *m = sc->sc_mbuf;
+#if defined(__FreeBSD__)
+ callout_stop(&sc->sc_tmo);
+#else
timeout_del(&sc->sc_tmo);
+#endif
sc->sc_mbuf = NULL;
sc->sc_ptr = NULL;
+#if defined(__FreeBSD__)
+ KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
+#endif
#if NBPFILTER > 0
if (ifp->if_bpf)
bpf_mtap(ifp->if_bpf, m);
@@ -357,3 +515,44 @@ pfsync_sendout(sc)
return (0);
}
+
+
+#if defined(__FreeBSD__)
+static int
+pfsync_modevent(module_t mod, int type, void *data)
+{
+ int error = 0;
+
+ switch (type) {
+ case MOD_LOAD:
+ LIST_INIT(&pfsync_list);
+ if_clone_attach(&pfsync_cloner);
+ printf("pfsync: $Name: $\n");
+ break;
+
+ case MOD_UNLOAD:
+ if_clone_detach(&pfsync_cloner);
+ while (!LIST_EMPTY(&pfsync_list))
+ pfsync_clone_destroy(
+ &LIST_FIRST(&pfsync_list)->sc_if);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+static moduledata_t pfsync_mod = {
+ "pfsync",
+ pfsync_modevent,
+ 0
+};
+
+#define PFSYNC_MODVER 1
+
+DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+MODULE_VERSION(pfsync, PFSYNC_MODVER);
+#endif /* __FreeBSD__ */
diff --git a/sys/contrib/pf/net/if_pfsync.h b/sys/contrib/pf/net/if_pfsync.h
index 9fff97fea8e1..ec1d74e230b3 100644
--- a/sys/contrib/pf/net/if_pfsync.h
+++ b/sys/contrib/pf/net/if_pfsync.h
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: if_pfsync.h,v 1.2 2002/12/11 18:31:26 mickey Exp $ */
/*
@@ -33,10 +34,17 @@
struct pfsync_softc {
struct ifnet sc_if;
+#if defined(__FreeBSD__)
+ struct callout sc_tmo;
+#else
struct timeout sc_tmo;
+#endif
struct mbuf *sc_mbuf; /* current cummulative mbuf */
struct pf_state *sc_ptr; /* current ongoing state */
int sc_count; /* number of states in one mtu */
+#if defined(__FreeBSD__)
+ LIST_ENTRY(pfsync_softc) sc_next;
+#endif
};
#endif
diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c
index 6d9517184247..81b74c3158f5 100644
--- a/sys/contrib/pf/net/pf.c
+++ b/sys/contrib/pf/net/pf.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: pf.c,v 1.390 2003/09/24 17:18:03 mcbride Exp $ */
/*
@@ -34,9 +35,22 @@
*
*/
+#if defined(__FreeBSD__)
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
+#if defined(__FreeBSD__) && __FreeBSD__ >= 5
+#include "opt_bpf.h"
+#define NBPFILTER DEV_BPF
+#include "opt_pf.h"
+#define NPFLOG DEV_PFLOG
+#define NPFSYNC DEV_PFSYNC
+#else
#include "bpfilter.h"
#include "pflog.h"
#include "pfsync.h"
+#endif
#include <sys/param.h>
#include <sys/systm.h>
@@ -46,7 +60,11 @@
#include <sys/socketvar.h>
#include <sys/kernel.h>
#include <sys/time.h>
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#else
#include <sys/pool.h>
+#endif
#include <net/if.h>
#include <net/if_types.h>
@@ -68,7 +86,9 @@
#include <netinet/udp_var.h>
#include <netinet/icmp_var.h>
+#if !defined(__FreeBSD__)
#include <dev/rndvar.h>
+#endif
#include <net/pfvar.h>
#include <net/if_pflog.h>
#include <net/if_pfsync.h>
@@ -78,12 +98,33 @@
#include <netinet/in_pcb.h>
#include <netinet/icmp6.h>
#include <netinet6/nd6.h>
+#if defined(__FreeBSD__)
+#include <netinet6/ip6_var.h>
+#include <netinet6/in6_pcb.h>
+#endif
#endif /* INET6 */
#ifdef ALTQ
#include <altq/if_altq.h>
#endif
+#if defined(__FreeBSD__)
+#include <machine/in_cksum.h>
+#if (__FreeBSD_version >= 500112)
+#include <sys/limits.h>
+#else
+#include <machine/limits.h>
+#endif
+#include <sys/ucred.h>
+#endif
+
+#if defined(__FreeBSD__)
+extern int ip_optcopy(struct ip *, struct ip *);
+#if (__FreeBSD_version < 501105)
+int ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu,
+ u_long if_hwassist_flags, int sw_csum);
+#endif
+#endif
#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
struct pf_state_tree;
@@ -105,12 +146,25 @@ u_int32_t ticket_altqs_active;
u_int32_t ticket_altqs_inactive;
u_int32_t ticket_pabuf;
+#if defined(__FreeBSD__)
+struct callout pf_expire_to; /* expire timeout */
+#else
struct timeout pf_expire_to; /* expire timeout */
+#endif
+
+#if defined(__FreeBSD__)
+uma_zone_t pf_tree_pl, pf_rule_pl, pf_addr_pl;
+uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
+#else
struct pool pf_tree_pl, pf_rule_pl, pf_addr_pl;
struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
+#endif
void pf_dynaddr_update(void *);
+#if defined(__FreeBSD__) && defined(HOOK_HACK)
+void pf_dynaddr_update_event(void *arg, struct ifnet *ifp);
+#endif
void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
void pf_print_state(struct pf_state *);
void pf_print_flags(u_int8_t);
@@ -205,9 +259,16 @@ int pf_check_proto_cksum(struct mbuf *, int, int,
int pf_addr_wrap_neq(struct pf_addr_wrap *,
struct pf_addr_wrap *);
+#if defined(__FreeBSD__)
+int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
+#endif
+#if defined(__FreeBSD__)
+struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
+#else
struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] =
{ { &pf_state_pl, PFSTATE_HIWAT }, { &pf_frent_pl, PFFRAG_FRENT_HIWAT } };
+#endif
#define STATE_LOOKUP() \
do { \
@@ -423,15 +484,30 @@ pf_insert_state(struct pf_state *state)
void
pf_purge_timeout(void *arg)
{
+#if defined(__FreeBSD__)
+ struct callout *to = arg;
+#else
struct timeout *to = arg;
+#endif
int s;
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
s = splsoftnet();
pf_purge_expired_states();
pf_purge_expired_fragments();
splx(s);
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
+#if defined(__FreeBSD__)
+ callout_reset(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz,
+ pf_purge_timeout, to);
+#else
timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz);
+#endif
}
u_int32_t
@@ -444,10 +520,19 @@ pf_state_expires(const struct pf_state *state)
/* handle all PFTM_* > PFTM_MAX here */
if (state->timeout == PFTM_PURGE)
+#if defined(__FreeBSD__)
+ return (time_second);
+#else
return (time.tv_sec);
+#endif
if (state->timeout == PFTM_UNTIL_PACKET)
return (0);
+#if defined(__FreeBSD__)
+ KASSERT((state->timeout < PFTM_MAX),
+ ("pf_state_expires: timeout > PFTM_MAX"));
+#else
KASSERT(state->timeout < PFTM_MAX);
+#endif
timeout = state->rule.ptr->timeout[state->timeout];
if (!timeout)
timeout = pf_default_rule.timeout[state->timeout];
@@ -465,7 +550,11 @@ pf_state_expires(const struct pf_state *state)
return (state->expire + timeout * (end - states) /
(end - start));
else
+#if defined(__FreeBSD__)
+ return (time_second);
+#else
return (time.tv_sec);
+#endif
}
return (state->expire + timeout);
}
@@ -479,7 +568,11 @@ pf_purge_expired_states(void)
for (cur = RB_MIN(pf_state_tree, &tree_ext_gwy); cur; cur = next) {
next = RB_NEXT(pf_state_tree, &tree_ext_gwy, cur);
+#if defined(__FreeBSD__)
+ if (pf_state_expires(cur->state) <= (u_int32_t)time_second) {
+#else
if (pf_state_expires(cur->state) <= time.tv_sec) {
+#endif
if (cur->state->src.state == PF_TCPS_PROXY_DST)
pf_send_tcp(cur->state->rule.ptr,
cur->state->af,
@@ -505,8 +598,14 @@ pf_purge_expired_states(void)
key.port[1] = cur->state->ext.port;
peer = RB_FIND(pf_state_tree, &tree_lan_ext, &key);
+#if defined(__FreeBSD__)
+ KASSERT((peer), ("peer null :%s", __FUNCTION__));
+ KASSERT((peer->state == cur->state),
+ ("peer->state != cur->state: %s", __FUNCTION__));
+#else
KASSERT(peer);
KASSERT(peer->state == cur->state);
+#endif
RB_REMOVE(pf_state_tree, &tree_lan_ext, peer);
#if NPFSYNC
@@ -583,6 +682,7 @@ pf_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
aw->p.dyn->addr = &aw->v.a.addr;
aw->p.dyn->af = af;
aw->p.dyn->undefined = 1;
+#if !defined(__FreeBSD__)
aw->p.dyn->hook_cookie = hook_establish(
aw->p.dyn->ifp->if_addrhooks, 1,
pf_dynaddr_update, aw->p.dyn);
@@ -591,10 +691,45 @@ pf_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af)
aw->p.dyn = NULL;
return (1);
}
+#elif defined(__FreeBSD__) && defined(HOOK_HACK)
+ PF_UNLOCK();
+ aw->p.dyn->hook_cookie = EVENTHANDLER_REGISTER(ifaddr_event,
+ pf_dynaddr_update_event, aw->p.dyn, EVENTHANDLER_PRI_ANY);
+ PF_LOCK();
+ if (aw->p.dyn->hook_cookie == NULL) {
+ pool_put(&pf_addr_pl, aw->p.dyn);
+ aw->p.dyn = NULL;
+ return (1);
+ }
+#else
+ /*
+ * XXX
+ * We have no hook_establish(9)/dohooks(9) kernel interfaces.
+ * This means that we do not aware of interface address changes(add,
+ * remove, etc). User should update pf rule manually after interface
+ * address changed. This may not be possible solution if you use xDSL.
+ * ipfw/ipfw2's approach with this situation(with me keyword) is not
+ * very efficient due to analyzing interface address during runtime.
+ * Another solution is to use a user-land daemon watching address
+ * changes with socket interface. Neither one is good.
+ * Supporting hook_establish(9) requries modification of in_control()
+ * located in netinet/in.c.
+ */
+#endif
pf_dynaddr_update(aw->p.dyn);
return (0);
}
+#if defined(__FreeBSD__) && defined(HOOK_HACK)
+void
+pf_dynaddr_update_event(void *arg, struct ifnet *ifp)
+{
+ PF_LOCK();
+ pf_dynaddr_update(arg);
+ PF_UNLOCK();
+}
+#endif
+
void
pf_dynaddr_update(void *p)
{
@@ -645,8 +780,20 @@ pf_dynaddr_remove(struct pf_addr_wrap *aw)
{
if (aw->type != PF_ADDR_DYNIFTL || aw->p.dyn == NULL)
return;
+#if !defined(__FreeBSD__)
hook_disestablish(aw->p.dyn->ifp->if_addrhooks,
aw->p.dyn->hook_cookie);
+#elif defined(__FreeBSD__) && defined(HOOK_HACK)
+ PF_UNLOCK();
+ EVENTHANDLER_DEREGISTER(ifaddr_event, aw->p.dyn->hook_cookie);
+ PF_LOCK();
+#else
+ /*
+ * XXX
+ * We have no hook_establish(9)/dohooks(9) kernel interfaces.
+ * See comments above function, pf_dynaddr_setup().
+ */
+#endif
pool_put(&pf_addr_pl, aw->p.dyn);
aw->p.dyn = NULL;
}
@@ -1101,6 +1248,12 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
struct ip6_hdr *h6;
#endif /* INET6 */
struct tcphdr *th;
+#if defined(__FreeBSD__)
+ struct ip *ip;
+#if (__FreeBSD_version < 501114)
+ struct route ro;
+#endif
+#endif
char *opt;
/* maximum segment size tcp option */
@@ -1206,12 +1359,44 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
h->ip_v = 4;
h->ip_hl = sizeof(*h) >> 2;
h->ip_tos = IPTOS_LOWDELAY;
- h->ip_len = htons(len);
+#if defined(__FreeBSD__)
+ h->ip_off = htons(path_mtu_discovery ? IP_DF : 0);
+#else
h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
+#endif
+ h->ip_len = htons(len);
h->ip_ttl = ttl ? ttl : ip_defttl;
h->ip_sum = 0;
+#if defined(__FreeBSD__)
+ ip = mtod(m, struct ip *);
+ /*
+ * XXX
+ * OpenBSD changed ip_len/ip_off byte ordering!
+ * Because FreeBSD assumes host byte ordering we need to
+ * change here.
+ */
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+#if (__FreeBSD_version < 501114)
+ bzero(&ro, sizeof(ro));
+ ip_rtaddr(ip->ip_dst, &ro);
+ PF_UNLOCK();
+ ip_output(m, (void *)NULL, &ro, 0, (void *)NULL,
+ (void *)NULL);
+ PF_LOCK();
+ if(ro.ro_rt) {
+ RTFREE(ro.ro_rt);
+ }
+#else /* __FreeBSD_version >= 501114 */
+ PF_UNLOCK();
+ ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
+ (void *)NULL);
+ PF_LOCK();
+#endif
+#else /* ! __FreeBSD__ */
ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL,
(void *)NULL);
+#endif
break;
#endif /* INET */
#ifdef INET6
@@ -1223,7 +1408,13 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af,
h6->ip6_vfc |= IPV6_VERSION;
h6->ip6_hlim = IPV6_DEFHLIM;
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+ ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+ PF_LOCK();
+#else
ip6_output(m, NULL, NULL, 0, NULL, NULL);
+#endif
break;
#endif /* INET6 */
}
@@ -1235,11 +1426,18 @@ pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
{
struct m_tag *mtag;
struct mbuf *m0;
+#if defined(__FreeBSD__)
+ struct ip *ip;
+#endif
mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
if (mtag == NULL)
return;
+#if defined(__FreeBSD__)
+ m0 = m_copypacket(m, M_DONTWAIT);
+#else
m0 = m_copy(m, 0, M_COPYALL);
+#endif
if (m0 == NULL) {
m_tag_free(mtag);
return;
@@ -1265,12 +1463,28 @@ pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
switch (af) {
#ifdef INET
case AF_INET:
- icmp_error(m0, type, code, 0, 0);
+#if defined(__FreeBSD__)
+ /* icmp_error() expects host byte ordering */
+ ip = mtod(m0, struct ip *);
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+ PF_UNLOCK();
+#endif
+ icmp_error(m0, type, code, 0, NULL);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
icmp6_error(m0, type, code, 0);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
break;
#endif /* INET6 */
}
@@ -1897,7 +2111,7 @@ pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
else
PF_POOLMASK(naddr,
&r->src.addr.v.a.addr,
- &r->src.addr.v.a.mask, saddr,
+ &r->src.addr.v.a.mask, daddr,
pd->af);
break;
}
@@ -1938,7 +2152,11 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, sa_family_t af,
{
struct pf_addr *saddr, *daddr;
u_int16_t sport, dport;
+#if defined(__FreeBSD__)
+ struct inpcbinfo *pi;
+#else
struct inpcbtable *tb;
+#endif
struct inpcb *inp;
*uid = UID_MAX;
@@ -1947,12 +2165,20 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, sa_family_t af,
case IPPROTO_TCP:
sport = pd->hdr.tcp->th_sport;
dport = pd->hdr.tcp->th_dport;
+#if defined(__FreeBSD__)
+ pi = &tcbinfo;
+#else
tb = &tcbtable;
+#endif
break;
case IPPROTO_UDP:
sport = pd->hdr.udp->uh_sport;
dport = pd->hdr.udp->uh_dport;
+#if defined(__FreeBSD__)
+ pi = &udbinfo;
+#else
tb = &udbtable;
+#endif
break;
default:
return (0);
@@ -1971,6 +2197,23 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, sa_family_t af,
}
switch(af) {
case AF_INET:
+#if defined(__FreeBSD__)
+#if (__FreeBSD_version >= 500043)
+ INP_INFO_RLOCK(pi); /* XXX LOR */
+#endif
+ inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
+ dport, 0, NULL);
+ if (inp == NULL) {
+ inp = in_pcblookup_hash(pi, saddr->v4, sport,
+ daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
+ if(inp == NULL) {
+#if (__FreeBSD_version >= 500043)
+ INP_INFO_RUNLOCK(pi);
+#endif
+ return (0);
+ }
+ }
+#else
inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
if (inp == NULL) {
inp = in_pcblookup(tb, &saddr->v4, sport, &daddr->v4,
@@ -1978,9 +2221,27 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, sa_family_t af,
if (inp == NULL)
return (0);
}
+#endif
break;
#ifdef INET6
case AF_INET6:
+#if defined(__FreeBSD__)
+#if (__FreeBSD_version >= 500043)
+ INP_INFO_RLOCK(pi);
+#endif
+ inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
+ &daddr->v6, dport, 0, NULL);
+ if (inp == NULL) {
+ inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
+ &daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
+ if (inp == NULL) {
+#if (__FreeBSD_version >= 500043)
+ INP_INFO_RUNLOCK(pi);
+#endif
+ return (0);
+ }
+ }
+#else
inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
dport);
if (inp == NULL) {
@@ -1989,14 +2250,27 @@ pf_socket_lookup(uid_t *uid, gid_t *gid, int direction, sa_family_t af,
if (inp == NULL)
return (0);
}
+#endif
break;
#endif /* INET6 */
default:
return (0);
}
+#if defined(__FreeBSD__)
+#if (__FreeBSD_version >= 500043)
+ INP_LOCK(inp);
+#endif
+ *uid = inp->inp_socket->so_cred->cr_uid;
+ *gid = inp->inp_socket->so_cred->cr_groups[0];
+#if (__FreeBSD_version >= 500043)
+ INP_UNLOCK(inp);
+ INP_INFO_RUNLOCK(pi);
+#endif
+#else
*uid = inp->inp_socket->so_euid;
*gid = inp->inp_socket->so_egid;
+#endif
return (1);
}
@@ -2099,7 +2373,15 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
dst->sin_family = AF_INET;
dst->sin_len = sizeof(*dst);
dst->sin_addr = addr->v4;
+#if defined(__FreeBSD__)
+#ifdef RTF_PRCLONING
+ rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
+#else /* !RTF_PRCLONING */
+ rtalloc_ign(&ro, RTF_CLONING);
+#endif
+#else /* ! __FreeBSD__ */
rtalloc_noclone(&ro, NO_CLONING);
+#endif
rt = ro.ro_rt;
break;
#endif /* INET */
@@ -2111,7 +2393,16 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
dst6->sin6_family = AF_INET6;
dst6->sin6_len = sizeof(*dst6);
dst6->sin6_addr = addr->v6;
+#if defined(__FreeBSD__)
+#ifdef RTF_PRCLONING
+ rtalloc_ign((struct route *)&ro6,
+ (RTF_CLONING | RTF_PRCLONING));
+#else /* !RTF_PRCLONING */
+ rtalloc_ign((struct route *)&ro6, RTF_CLONING);
+#endif
+#else /* ! __FreeBSD__ */
rtalloc_noclone((struct route *)&ro6, NO_CLONING);
+#endif
rt = ro6.ro_rt;
break;
#endif /* INET6 */
@@ -2284,7 +2575,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
if (r->log) {
if (rewrite)
- m_copyback(m, off, sizeof(*th), th);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset);
}
@@ -2417,8 +2708,13 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
s->dst.max_win = 1;
s->src.state = TCPS_SYN_SENT;
s->dst.state = TCPS_CLOSED;
+#if defined(__FreeBSD__)
+ s->creation = time_second;
+ s->expire = time_second;
+#else
s->creation = time.tv_sec;
s->expire = time.tv_sec;
+#endif
s->timeout = PFTM_TCP_FIRST_PACKET;
s->packets[0] = 1;
s->bytes[0] = pd->tot_len;
@@ -2470,7 +2766,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
/* copy back packet headers if we performed NAT operations */
if (rewrite)
- m_copyback(m, off, sizeof(*th), th);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
return (PF_PASS);
}
@@ -2602,7 +2898,7 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
if (r->log) {
if (rewrite)
- m_copyback(m, off, sizeof(*uh), uh);
+ m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset);
}
@@ -2689,8 +2985,13 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
}
s->src.state = PFUDPS_SINGLE;
s->dst.state = PFUDPS_NO_TRAFFIC;
+#if defined(__FreeBSD__)
+ s->creation = time_second;
+ s->expire = time_second;
+#else
s->creation = time.tv_sec;
s->expire = time.tv_sec;
+#endif
s->timeout = PFTM_UDP_FIRST_PACKET;
s->packets[0] = 1;
s->bytes[0] = pd->tot_len;
@@ -2705,7 +3006,7 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
/* copy back packet headers if we performed NAT operations */
if (rewrite)
- m_copyback(m, off, sizeof(*uh), uh);
+ m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
return (PF_PASS);
}
@@ -2875,7 +3176,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
#ifdef INET6
if (rewrite)
m_copyback(m, off, sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
#endif /* INET6 */
PFLOG_PACKET(ifp, h, m, af, direction, reason, r, a, ruleset);
}
@@ -2937,8 +3238,14 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
s->gwy.port = icmpid;
}
+
+#if defined(__FreeBSD__)
+ s->creation = time_second;
+ s->expire = time_second;
+#else
s->creation = time.tv_sec;
s->expire = time.tv_sec;
+#endif
s->timeout = PFTM_ICMP_FIRST_PACKET;
s->packets[0] = 1;
s->bytes[0] = pd->tot_len;
@@ -2955,7 +3262,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
/* copy back packet headers if we performed IPv6 NAT operations */
if (rewrite)
m_copyback(m, off, sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
#endif /* INET6 */
return (PF_PASS);
@@ -3164,8 +3471,13 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
}
s->src.state = PFOTHERS_SINGLE;
s->dst.state = PFOTHERS_NO_TRAFFIC;
+#if defined(__FreeBSD__)
+ s->creation = time_second;
+ s->expire = time_second;
+#else
s->creation = time.tv_sec;
s->expire = time.tv_sec;
+#endif
s->timeout = PFTM_OTHER_FIRST_PACKET;
s->packets[0] = 1;
s->bytes[0] = pd->tot_len;
@@ -3523,7 +3835,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
src->state = dst->state = TCPS_TIME_WAIT;
/* update expire time */
+#if defined(__FreeBSD__)
+ (*state)->expire = time_second;
+#else
(*state)->expire = time.tv_sec;
+#endif
if (src->state >= TCPS_FIN_WAIT_2 &&
dst->state >= TCPS_FIN_WAIT_2)
(*state)->timeout = PFTM_TCP_CLOSED;
@@ -3664,10 +3980,10 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp,
pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
&th->th_sum, &(*state)->lan.addr,
(*state)->lan.port, 0, pd->af);
- m_copyback(m, off, sizeof(*th), th);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
} else if (copyback) {
/* Copyback sequence modulation or stateful scrub changes */
- m_copyback(m, off, sizeof(*th), th);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
}
(*state)->rule.ptr->packets++;
@@ -3721,7 +4037,11 @@ pf_test_state_udp(struct pf_state **state, int direction, struct ifnet *ifp,
dst->state = PFUDPS_MULTIPLE;
/* update expire time */
+#if defined(__FreeBSD__)
+ (*state)->expire = time_second;
+#else
(*state)->expire = time.tv_sec;
+#endif
if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
(*state)->timeout = PFTM_UDP_MULTIPLE;
else
@@ -3737,7 +4057,7 @@ pf_test_state_udp(struct pf_state **state, int direction, struct ifnet *ifp,
pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
&uh->uh_sum, &(*state)->lan.addr,
(*state)->lan.port, 1, pd->af);
- m_copyback(m, off, sizeof(*uh), uh);
+ m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
}
(*state)->rule.ptr->packets++;
@@ -3812,7 +4132,11 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
dirndx = (direction == (*state)->direction) ? 0 : 1;
(*state)->packets[dirndx]++;
(*state)->bytes[dirndx] += pd->tot_len;
+#if defined(__FreeBSD__)
+ (*state)->expire = time_second;
+#else
(*state)->expire = time.tv_sec;
+#endif
(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
/* translate source/destination address, if necessary */
@@ -3833,7 +4157,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
&(*state)->gwy.addr, 0);
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
break;
#endif /* INET6 */
}
@@ -3853,7 +4177,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
&(*state)->lan.addr, 0);
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
break;
#endif /* INET6 */
}
@@ -4044,24 +4368,24 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
#ifdef INET
case AF_INET:
m_copyback(m, off, ICMP_MINLEN,
- pd->hdr.icmp);
+ (caddr_t)pd->hdr.icmp);
m_copyback(m, ipoff2, sizeof(h2),
- &h2);
+ (caddr_t)&h2);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6),
- &h2_6);
+ (caddr_t)&h2_6);
break;
#endif /* INET6 */
}
- m_copyback(m, off2, 8, &th);
+ m_copyback(m, off2, 8, (caddr_t)&th);
} else if (src->seqdiff) {
- m_copyback(m, off2, 8, &th);
+ m_copyback(m, off2, 8, (caddr_t)&th);
}
return (PF_PASS);
@@ -4106,21 +4430,23 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
#ifdef INET
case AF_INET:
m_copyback(m, off, ICMP_MINLEN,
- pd->hdr.icmp);
- m_copyback(m, ipoff2, sizeof(h2), &h2);
+ (caddr_t)pd->hdr.icmp);
+ m_copyback(m, ipoff2, sizeof(h2),
+ (caddr_t)&h2);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6),
- &h2_6);
+ (caddr_t)&h2_6);
break;
#endif /* INET6 */
}
- m_copyback(m, off2, sizeof(uh), &uh);
+ m_copyback(m, off2, sizeof(uh),
+ (caddr_t)&uh);
}
return (PF_PASS);
@@ -4162,9 +4488,12 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
pd2.ip_sum, icmpsum,
pd->ip_sum, 0, AF_INET);
}
- m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp);
- m_copyback(m, ipoff2, sizeof(h2), &h2);
- m_copyback(m, off2, ICMP_MINLEN, &iih);
+ m_copyback(m, off, ICMP_MINLEN,
+ (caddr_t)pd->hdr.icmp);
+ m_copyback(m, ipoff2, sizeof(h2),
+ (caddr_t)&h2);
+ m_copyback(m, off2, ICMP_MINLEN,
+ (caddr_t)&iih);
}
return (PF_PASS);
@@ -4208,10 +4537,11 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
pd->ip_sum, 0, AF_INET6);
}
m_copyback(m, off, sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
- m_copyback(m, ipoff2, sizeof(h2_6), &h2_6);
+ (caddr_t)pd->hdr.icmp6);
+ m_copyback(m, ipoff2, sizeof(h2_6),
+ (caddr_t)&h2_6);
m_copyback(m, off2, sizeof(struct icmp6_hdr),
- &iih);
+ (caddr_t)&iih);
}
return (PF_PASS);
@@ -4248,17 +4578,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp,
#ifdef INET
case AF_INET:
m_copyback(m, off, ICMP_MINLEN,
- pd->hdr.icmp);
- m_copyback(m, ipoff2, sizeof(h2), &h2);
+ (caddr_t)pd->hdr.icmp);
+ m_copyback(m, ipoff2, sizeof(h2),
+ (caddr_t)&h2);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
m_copyback(m, off,
sizeof(struct icmp6_hdr),
- pd->hdr.icmp6);
+ (caddr_t)pd->hdr.icmp6);
m_copyback(m, ipoff2, sizeof(h2_6),
- &h2_6);
+ (caddr_t)&h2_6);
break;
#endif /* INET6 */
}
@@ -4308,7 +4639,11 @@ pf_test_state_other(struct pf_state **state, int direction, struct ifnet *ifp,
dst->state = PFOTHERS_MULTIPLE;
/* update expire time */
+#if defined(__FreeBSD__)
+ (*state)->expire = time_second;
+#else
(*state)->expire = time.tv_sec;
+#endif
if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
(*state)->timeout = PFTM_OTHER_MULTIPLE;
else
@@ -4423,7 +4758,15 @@ pf_routable(struct pf_addr *addr, sa_family_t af)
dst->sin_family = af;
dst->sin_len = sizeof(*dst);
dst->sin_addr = addr->v4;
+#if defined(__FreeBSD__)
+#ifdef RTF_PRCLONING
+ rtalloc_ign(&ro, (RTF_CLONING|RTF_PRCLONING));
+#else /* !RTF_PRCLONING */
+ rtalloc_ign(&ro, RTF_CLONING);
+#endif
+#else /* ! __FreeBSD__ */
rtalloc_noclone(&ro, NO_CLONING);
+#endif
if (ro.ro_rt != NULL) {
ret = 1;
@@ -4434,6 +4777,168 @@ pf_routable(struct pf_addr *addr, sa_family_t af)
}
#ifdef INET
+
+#if defined(__FreeBSD__) && (__FreeBSD_version < 501105)
+int
+ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu,
+ u_long if_hwassist_flags, int sw_csum)
+{
+ int error = 0;
+ int hlen = ip->ip_hl << 2;
+ int len = (mtu - hlen) & ~7; /* size of payload in each fragment */
+ int off;
+ struct mbuf *m0 = *m_frag; /* the original packet */
+ int firstlen;
+ struct mbuf **mnext;
+ int nfrags;
+
+ if (ip->ip_off & IP_DF) { /* Fragmentation not allowed */
+ ipstat.ips_cantfrag++;
+ return EMSGSIZE;
+ }
+
+ /*
+ * Must be able to put at least 8 bytes per fragment.
+ */
+ if (len < 8)
+ return EMSGSIZE;
+
+ /*
+ * If the interface will not calculate checksums on
+ * fragmented packets, then do it here.
+ */
+ if (m0->m_pkthdr.csum_flags & CSUM_DELAY_DATA &&
+ (if_hwassist_flags & CSUM_IP_FRAGS) == 0) {
+ in_delayed_cksum(m0);
+ m0->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
+ }
+
+ if (len > PAGE_SIZE) {
+ /*
+ * Fragment large datagrams such that each segment
+ * contains a multiple of PAGE_SIZE amount of data,
+ * plus headers. This enables a receiver to perform
+ * page-flipping zero-copy optimizations.
+ *
+ * XXX When does this help given that sender and receiver
+ * could have different page sizes, and also mtu could
+ * be less than the receiver's page size ?
+ */
+ int newlen;
+ struct mbuf *m;
+
+ for (m = m0, off = 0; m && (off+m->m_len) <= mtu; m = m->m_next)
+ off += m->m_len;
+
+ /*
+ * firstlen (off - hlen) must be aligned on an
+ * 8-byte boundary
+ */
+ if (off < hlen)
+ goto smart_frag_failure;
+ off = ((off - hlen) & ~7) + hlen;
+ newlen = (~PAGE_MASK) & mtu;
+ if ((newlen + sizeof (struct ip)) > mtu) {
+ /* we failed, go back the default */
+smart_frag_failure:
+ newlen = len;
+ off = hlen + len;
+ }
+ len = newlen;
+
+ } else {
+ off = hlen + len;
+ }
+
+ firstlen = off - hlen;
+ mnext = &m0->m_nextpkt; /* pointer to next packet */
+
+ /*
+ * Loop through length of segment after first fragment,
+ * make new header and copy data of each part and link onto chain.
+ * Here, m0 is the original packet, m is the fragment being created.
+ * The fragments are linked off the m_nextpkt of the original
+ * packet, which after processing serves as the first fragment.
+ */
+ for (nfrags = 1; off < ip->ip_len; off += len, nfrags++) {
+ struct ip *mhip; /* ip header on the fragment */
+ struct mbuf *m;
+ int mhlen = sizeof (struct ip);
+
+ MGETHDR(m, M_DONTWAIT, MT_HEADER);
+ if (m == 0) {
+ error = ENOBUFS;
+ ipstat.ips_odropped++;
+ goto done;
+ }
+ m->m_flags |= (m0->m_flags & M_MCAST) | M_FRAG;
+ /*
+ * In the first mbuf, leave room for the link header, then
+ * copy the original IP header including options. The payload
+ * goes into an additional mbuf chain returned by m_copy().
+ */
+ m->m_data += max_linkhdr;
+ mhip = mtod(m, struct ip *);
+ *mhip = *ip;
+ if (hlen > sizeof (struct ip)) {
+ mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
+ mhip->ip_v = IPVERSION;
+ mhip->ip_hl = mhlen >> 2;
+ }
+ m->m_len = mhlen;
+ /* XXX do we need to add ip->ip_off below ? */
+ mhip->ip_off = ((off - hlen) >> 3) + ip->ip_off;
+ if (off + len >= ip->ip_len) { /* last fragment */
+ len = ip->ip_len - off;
+ m->m_flags |= M_LASTFRAG;
+ } else
+ mhip->ip_off |= IP_MF;
+ mhip->ip_len = htons((u_short)(len + mhlen));
+ m->m_next = m_copy(m0, off, len);
+ if (m->m_next == 0) { /* copy failed */
+ m_free(m);
+ error = ENOBUFS; /* ??? */
+ ipstat.ips_odropped++;
+ goto done;
+ }
+ m->m_pkthdr.len = mhlen + len;
+ m->m_pkthdr.rcvif = (struct ifnet *)0;
+#ifdef MAC
+ mac_create_fragment(m0, m);
+#endif
+ m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags;
+ mhip->ip_off = htons(mhip->ip_off);
+ mhip->ip_sum = 0;
+ if (sw_csum & CSUM_DELAY_IP)
+ mhip->ip_sum = in_cksum(m, mhlen);
+ *mnext = m;
+ mnext = &m->m_nextpkt;
+ }
+ ipstat.ips_ofragments += nfrags;
+
+ /* set first marker for fragment chain */
+ m0->m_flags |= M_FIRSTFRAG | M_FRAG;
+ m0->m_pkthdr.csum_data = nfrags;
+
+ /*
+ * Update first fragment by trimming what's been copied out
+ * and updating header.
+ */
+ m_adj(m0, hlen + firstlen - ip->ip_len);
+ m0->m_pkthdr.len = hlen + firstlen;
+ ip->ip_len = htons((u_short)m0->m_pkthdr.len);
+ ip->ip_off |= IP_MF;
+ ip->ip_off = htons(ip->ip_off);
+ ip->ip_sum = 0;
+ if (sw_csum & CSUM_DELAY_IP)
+ ip->ip_sum = in_cksum(m0, hlen);
+
+done:
+ *m_frag = m0;
+ return error;
+}
+#endif /* __FreeBSD__ && __FreeBSD_version > 501105 */
+
void
pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
struct pf_state *s)
@@ -4447,6 +4952,9 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
struct m_tag *mtag;
struct pf_addr naddr;
int error = 0;
+#if defined(__FreeBSD__)
+ int sw_csum;
+#endif
if (m == NULL || *m == NULL || r == NULL ||
(dir != PF_IN && dir != PF_OUT) || oifp == NULL)
@@ -4461,7 +4969,11 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
m_tag_prepend(m0, mtag);
}
+#if defined(__FreeBSD__)
+ m0 = m_dup(*m, M_DONTWAIT);
+#else
m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT);
+#endif
if (m0 == NULL)
return;
} else {
@@ -4525,15 +5037,68 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
}
if (oifp != ifp && mtag == NULL) {
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+ if (pf_test(PF_OUT, ifp, &m0) != PF_PASS) {
+ PF_LOCK();
+ goto bad;
+ } else if (m0 == NULL) {
+ PF_LOCK();
+ goto done;
+ }
+ PF_LOCK();
+#else
if (pf_test(PF_OUT, ifp, &m0) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
+#endif
if (m0->m_len < sizeof(struct ip))
panic("pf_route: m0->m_len < sizeof(struct ip)");
ip = mtod(m0, struct ip *);
}
+#if defined(__FreeBSD__)
+ /* Copied from FreeBSD 5.1-CURRENT ip_output. */
+ m0->m_pkthdr.csum_flags |= CSUM_IP;
+ sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
+ if (sw_csum & CSUM_DELAY_DATA) {
+ /*
+ * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
+ */
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off); /* XXX: needed? */
+ in_delayed_cksum(m0);
+ HTONS(ip->ip_len);
+ HTONS(ip->ip_off);
+ sw_csum &= ~CSUM_DELAY_DATA;
+ }
+ m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
+
+ if (ntohs(ip->ip_len) <= ifp->if_mtu ||
+ (ifp->if_hwassist & CSUM_FRAGMENT &&
+ ((ip->ip_off & htons(IP_DF)) == 0))) {
+ /*
+ * ip->ip_len = htons(ip->ip_len);
+ * ip->ip_off = htons(ip->ip_off);
+ */
+ ip->ip_sum = 0;
+ if (sw_csum & CSUM_DELAY_IP) {
+ /* From KAME */
+ if (ip->ip_v == IPVERSION &&
+ (ip->ip_hl << 2) == sizeof(*ip)) {
+ ip->ip_sum = in_cksum_hdr(ip);
+ } else {
+ ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
+ }
+ }
+ PF_UNLOCK();
+ error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt);
+ PF_LOCK();
+ goto done;
+ }
+
+#else
/* Copied from ip_output. */
if (ntohs(ip->ip_len) <= ifp->if_mtu) {
if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
@@ -4552,7 +5117,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
goto done;
}
-
+#endif
/*
* Too large for interface; fragment if possible.
* Must be able to put at least 8 bytes per fragment.
@@ -4560,25 +5125,56 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (ip->ip_off & htons(IP_DF)) {
ipstat.ips_cantfrag++;
if (r->rt != PF_DUPTO) {
+#if defined(__FreeBSD__)
+ /* icmp_error() expects host byte ordering */
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+ PF_UNLOCK();
+#endif
icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
ifp);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
goto done;
} else
goto bad;
}
m1 = m0;
+#if defined(__FreeBSD__)
+ /*
+ * XXX: is cheaper + less error prone than own function
+ */
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+ error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
+#else
error = ip_fragment(m0, ifp, ifp->if_mtu);
+#endif
+#if defined(__FreeBSD__)
+ if (error)
+#else
if (error == EMSGSIZE)
+#endif
goto bad;
for (m0 = m1; m0; m0 = m1) {
m1 = m0->m_nextpkt;
m0->m_nextpkt = 0;
+#if defined(__FreeBSD__)
+ if (error == 0) {
+ PF_UNLOCK();
+ error = (*ifp->if_output)(ifp, m0, sintosa(dst),
+ NULL);
+ PF_LOCK();
+ } else
+#else
if (error == 0)
error = (*ifp->if_output)(ifp, m0, sintosa(dst),
NULL);
else
+#endif
m_freem(m0);
}
@@ -4626,7 +5222,11 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
goto bad;
m_tag_prepend(m0, mtag);
}
+#if defined(__FreeBSD__)
+ m0 = m_dup(*m, M_DONTWAIT);
+#else
m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT);
+#endif
if (m0 == NULL)
return;
} else {
@@ -4652,7 +5252,13 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (mtag == NULL)
goto bad;
m_tag_prepend(m0, mtag);
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+ ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
+ PF_LOCK();
+#else
ip6_output(m0, NULL, NULL, 0, NULL, NULL);
+#endif
return;
}
@@ -4682,10 +5288,22 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (mtag == NULL)
goto bad;
m_tag_prepend(m0, mtag);
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+ if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS) {
+ PF_LOCK();
+ goto bad;
+ } else if (m0 == NULL) {
+ PF_LOCK();
+ goto done;
+ }
+ PF_LOCK();
+#else
if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
+#endif
}
}
@@ -4696,12 +5314,26 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr))
dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
error = nd6_output(ifp, ifp, m0, dst, NULL);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
} else {
in6_ifstat_inc(ifp, ifs6_in_toobig);
+#if defined(__FreeBSD__)
+ if (r->rt != PF_DUPTO) {
+ PF_UNLOCK();
+ icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
+ PF_LOCK();
+ } else
+#else
if (r->rt != PF_DUPTO)
icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
else
+#endif
goto bad;
}
@@ -4717,6 +5349,135 @@ bad:
#endif /* INET6 */
+#if defined(__FreeBSD__)
+/*
+ * XXX
+ * FreeBSD supports cksum offload for the following drivers.
+ * em(4), gx(4), lge(4), nge(4), ti(4), xl(4)
+ * If we can make full use of it we would outperform ipfw/ipfilter in
+ * very heavy traffic.
+ * I have not tested 'cause I don't have NICs that supports cksum offload.
+ * (There might be problems. Typical phenomena would be
+ * 1. No route message for UDP packet.
+ * 2. No connection acceptance from external hosts regardless of rule set.)
+ */
+int
+pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
+{
+ u_int16_t sum = 0;
+ int hw_assist = 0;
+ struct ip *ip;
+
+ if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
+ return (1);
+ if (m->m_pkthdr.len < off + len)
+ return (1);
+
+ switch (p) {
+ case IPPROTO_TCP:
+ if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
+ if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
+ sum = m->m_pkthdr.csum_data;
+ } else {
+ ip = mtod(m, struct ip *);
+ sum = in_pseudo(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr,
+ htonl(m->m_pkthdr.csum_data +
+ IPPROTO_TCP) + ip->ip_len);
+ }
+ sum ^= 0xffff;
+ ++hw_assist;
+ }
+ break;
+ case IPPROTO_UDP:
+ if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
+ if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
+ sum = m->m_pkthdr.csum_data;
+ } else {
+ ip = mtod(m, struct ip *);
+ sum = in_pseudo(ip->ip_src.s_addr,
+ ip->ip_dst.s_addr, htonl((u_short)len +
+ m->m_pkthdr.csum_data + IPPROTO_UDP));
+ }
+ sum ^= 0xffff;
+ ++hw_assist;
+ }
+ break;
+ case IPPROTO_ICMP:
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+#endif /* INET6 */
+ break;
+ default:
+ return (1);
+ }
+
+ if (!hw_assist) {
+ switch (af) {
+ case AF_INET:
+ if (p == IPPROTO_ICMP) {
+ if (m->m_len < off)
+ return (1);
+ m->m_data += off;
+ m->m_len -= off;
+ sum = in_cksum(m, len);
+ m->m_data -= off;
+ m->m_len += off;
+ } else {
+ if (m->m_len < sizeof(struct ip))
+ return (1);
+ sum = in4_cksum(m, p, off, len);
+ if (sum == 0) {
+ m->m_pkthdr.csum_flags |=
+ (CSUM_DATA_VALID |
+ CSUM_PSEUDO_HDR);
+ m->m_pkthdr.csum_data = 0xffff;
+ }
+ }
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (m->m_len < sizeof(struct ip6_hdr))
+ return (1);
+ sum = in6_cksum(m, p, off, len);
+ /*
+ * XXX
+ * IPv6 H/W cksum off-load not supported yet!
+ *
+ * if (sum == 0) {
+ * m->m_pkthdr.csum_flags |=
+ * (CSUM_DATA_VALID|CSUM_PSEUDO_HDR);
+ * m->m_pkthdr.csum_data = 0xffff;
+ *}
+ */
+ break;
+#endif /* INET6 */
+ default:
+ return (1);
+ }
+ }
+ if (sum) {
+ switch (p) {
+ case IPPROTO_TCP:
+ tcpstat.tcps_rcvbadsum++;
+ break;
+ case IPPROTO_UDP:
+ udpstat.udps_badsum++;
+ break;
+ case IPPROTO_ICMP:
+ icmpstat.icps_checksum++;
+ break;
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+ icmp6stat.icp6s_checksum++;
+ break;
+#endif /* INET6 */
+ }
+ return (1);
+ }
+ return (0);
+}
+#else
/*
* check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
* off is the offset where the protocol header starts
@@ -4804,6 +5565,7 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t a
m->m_pkthdr.csum |= flag_ok;
return (0);
}
+#endif
#ifdef INET
int
@@ -4819,14 +5581,25 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
int off;
int pqid = 0;
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
if (!pf_status.running ||
- (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL))
- return (PF_PASS);
+ (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
+ return (PF_PASS);
+ }
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 501000)
+ M_ASSERTPKTHDR(m);
+#else
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("non-M_PKTHDR is passed to pf_test");
#endif
+#endif
if (m->m_pkthdr.len < (int)sizeof(*h)) {
action = PF_DROP;
@@ -5028,6 +5801,10 @@ done:
/* pf_route can free the mbuf causing *m0 to become NULL */
pf_route(m0, r, dir, ifp, s);
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
+
return (action);
}
#endif /* INET */
@@ -5045,14 +5822,26 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
struct pf_pdesc pd;
int off, terminal = 0;
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
+
if (!pf_status.running ||
- (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL))
+ (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
return (PF_PASS);
+ }
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 501000)
+ M_ASSERTPKTHDR(m);
+#else
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("non-M_PKTHDR is passed to pf_test");
#endif
+#endif
if (m->m_pkthdr.len < (int)sizeof(*h)) {
action = PF_DROP;
@@ -5258,6 +6047,9 @@ done:
/* pf_route6 can free the mbuf causing *m0 to become NULL */
pf_route6(m0, r, dir, ifp, s);
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
return (action);
}
#endif /* INET6 */
diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c
index 0607f96b7e6c..2b156ad632e3 100644
--- a/sys/contrib/pf/net/pf_ioctl.c
+++ b/sys/contrib/pf/net/pf_ioctl.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: pf_ioctl.c,v 1.81 2003/08/22 21:50:34 david Exp $ */
/*
@@ -34,6 +35,11 @@
*
*/
+#if defined(__FreeBSD__)
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
@@ -43,9 +49,13 @@
#include <sys/socketvar.h>
#include <sys/kernel.h>
#include <sys/time.h>
+#include <sys/malloc.h>
+#if defined(__FreeBSD__)
+#include <sys/conf.h>
+#else
#include <sys/timeout.h>
#include <sys/pool.h>
-#include <sys/malloc.h>
+#endif
#include <net/if.h>
#include <net/if_types.h>
@@ -63,24 +73,58 @@
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet/in_pcb.h>
+#if defined(__FreeBSD__) && (__FreeBSD_version < 501108)
+#include <netinet6/ip6protosw.h>
+#endif
#endif /* INET6 */
#ifdef ALTQ
#include <altq/altq.h>
#endif
+#if defined(__FreeBSD__)
+#if (__FreeBSD_version >= 500112)
+#include <sys/limits.h>
+#else
+#include <machine/limits.h>
+#endif
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#if __FreeBSD_version < 501108
+#include <sys/protosw.h>
+#endif
+#include <net/pfil.h>
+#endif /* __FreeBSD__ */
+
+#if defined(__FreeBSD__)
+void init_zone_var(void);
+void cleanup_pf_zone(void);
+int pfattach(void);
+#else
void pfattach(int);
int pfopen(dev_t, int, int, struct proc *);
int pfclose(dev_t, int, int, struct proc *);
+#endif
struct pf_pool *pf_get_pool(char *, char *, u_int32_t,
u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t);
int pf_get_ruleset_number(u_int8_t);
void pf_init_ruleset(struct pf_ruleset *);
void pf_mv_pool(struct pf_palist *, struct pf_palist *);
void pf_empty_pool(struct pf_palist *);
+#if defined(__FreeBSD__)
+int pfioctl(dev_t, u_long, caddr_t, int, struct thread *);
+#else
int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
+#endif
+#if defined(__FreeBSD__)
+extern struct callout pf_expire_to;
+#if __FreeBSD_version < 501108
+extern struct protosw inetsw[];
+#endif
+#else
extern struct timeout pf_expire_to;
+#endif
struct pf_rule pf_default_rule;
@@ -89,6 +133,244 @@ TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags);
#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
+
+#if defined(__FreeBSD__)
+static dev_t pf_dev;
+
+/*
+ * XXX - These are new and need to be checked when moveing to a new version
+ */
+static int pf_beginrules(void *addr);
+static int pf_commitrules(void *addr);
+#if defined(ALTQ)
+static int pf_beginaltqs(void *addr);
+static int pf_commitaltqs(void *addr);
+static int pf_stopaltq(void);
+#endif
+static void pf_clearstates(void);
+static int pf_clear_tables(void *addr);
+/*
+ * XXX - These are new and need to be checked when moveing to a new version
+ */
+
+#if (__FreeBSD_version < 501108)
+static int pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir,
+ struct mbuf **m);
+static int pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir,
+ struct mbuf **m);
+#if defined(INET6)
+static int pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir,
+ struct mbuf **m);
+static int pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir,
+ struct mbuf **m);
+#endif
+#else /* (__FreeBSD_version >= 501108) */
+static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp,
+ int dir);
+static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp,
+ int dir);
+#if defined(INET6)
+static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp,
+ int dir);
+static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp,
+ int dir);
+#endif
+#endif /* (__FreeBSD_version >= 501108) */
+static int hook_pf(void);
+static int dehook_pf(void);
+static int shutdown_pf(void);
+static int pf_load(void);
+static int pf_unload(void);
+
+
+
+static struct cdevsw pf_cdevsw = {
+#if (__FreeBSD_version < 500105)
+ /* open */ noopen,
+ /* close */ noclose,
+ /* read */ noread,
+ /* write */ nowrite,
+ /* ioctl */ pfioctl,
+ /* poll */ nopoll,
+ /* mmap */ nommap,
+ /* strategy */ nostrategy,
+ /* name */ PF_NAME,
+ /* maj */ PF_CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+ /* kqfilter */ nokqfilter,
+#elif (__FreeBSD_version < 501110)
+ .d_open = noopen,
+ .d_close = noclose,
+ .d_read = noread,
+ .d_write = nowrite,
+ .d_ioctl = pfioctl,
+ .d_poll = nopoll,
+ .d_mmap = nommap,
+ .d_strategy = nostrategy,
+ .d_name = PF_NAME,
+ .d_maj = MAJOR_AUTO, /* PF_CDEV_MAJOR */
+ .d_dump = nodump,
+ .d_flags = 0,
+ .d_kqfilter = nokqfilter,
+#else
+ .d_ioctl = pfioctl,
+ .d_name = PF_NAME,
+ .d_version = D_VERSION,
+#endif
+};
+#endif /* __FreeBSD__ */
+
+#if defined(__FreeBSD__)
+static volatile int pf_pfil_hooked = 0;
+struct mtx pf_task_mtx;
+
+void
+init_pf_mutex(void)
+{
+ mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF);
+/*
+ * pf_altq_mtx is initialized at altq_subr.c.
+ *
+ * #if defined(ALTQ) && !defined(ALTQ3_COMPAT)
+ * mtx_init(&pf_altq_mtx, "pf altq mtx", NULL, MTX_DEF);
+ * #endif
+ */
+}
+
+void
+destroy_pf_mutex(void)
+{
+ mtx_destroy(&pf_task_mtx);
+/*
+ * pf_altq_mtx is initialized at altq_subr.c.
+ *
+ * #if defined(ALTQ) && !defined(ALTQ3_COMPAT)
+ * mtx_destroy(&pf_altq_mtx);
+ * #endif
+ */
+}
+
+void
+init_zone_var(void)
+{
+ pf_tree_pl = pf_rule_pl = pf_addr_pl = NULL;
+ pf_state_pl = pf_altq_pl = pf_pooladdr_pl = NULL;
+ pf_frent_pl = pf_frag_pl = pf_cache_pl = pf_cent_pl = NULL;
+ pf_state_scrub_pl = NULL;
+ pfr_ktable_pl = pfr_kentry_pl = NULL;
+}
+
+void
+cleanup_pf_zone(void)
+{
+ UMA_DESTROY(pf_tree_pl);
+ UMA_DESTROY(pf_rule_pl);
+ UMA_DESTROY(pf_addr_pl);
+ UMA_DESTROY(pf_state_pl);
+ UMA_DESTROY(pf_altq_pl);
+ UMA_DESTROY(pf_pooladdr_pl);
+ UMA_DESTROY(pf_frent_pl);
+ UMA_DESTROY(pf_frag_pl);
+ UMA_DESTROY(pf_cache_pl);
+ UMA_DESTROY(pf_cent_pl);
+ UMA_DESTROY(pfr_ktable_pl);
+ UMA_DESTROY(pfr_kentry_pl);
+ UMA_DESTROY(pf_state_scrub_pl);
+}
+#endif /* __FreeBSD__ */
+
+#if defined(__FreeBSD__)
+int
+pfattach(void)
+{
+ u_int32_t *my_timeout = pf_default_rule.timeout;
+ int error = 1;
+
+ do {
+ UMA_CREATE(pf_tree_pl, struct pf_tree_node, "pftrpl");
+ UMA_CREATE(pf_rule_pl, struct pf_rule, "pfrulepl");
+ UMA_CREATE(pf_addr_pl, struct pf_addr_dyn, "pfaddrpl");
+ UMA_CREATE(pf_state_pl, struct pf_state, "pfstatepl");
+ UMA_CREATE(pf_altq_pl, struct pf_altq, "pfaltqpl");
+ UMA_CREATE(pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl");
+ UMA_CREATE(pfr_ktable_pl, struct pfr_ktable, "pfrktable");
+ UMA_CREATE(pfr_kentry_pl, struct pfr_kentry, "pfrkentry");
+ UMA_CREATE(pf_frent_pl, struct pf_frent, "pffrent");
+ UMA_CREATE(pf_frag_pl, struct pf_fragment, "pffrag");
+ UMA_CREATE(pf_cache_pl, struct pf_fragment, "pffrcache");
+ UMA_CREATE(pf_cent_pl, struct pf_frcache, "pffrcent");
+ UMA_CREATE(pf_state_scrub_pl, struct pf_state_scrub,
+ "pfstatescrub");
+ error = 0;
+ } while(0);
+ if (error) {
+ cleanup_pf_zone();
+ return (error);
+ }
+ pfr_initialize();
+ if ( (error = pf_osfp_initialize()) ) {
+ cleanup_pf_zone();
+ pf_osfp_cleanup();
+ return (error);
+ }
+
+ pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl;
+ pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT;
+ pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl;
+ pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT;
+ uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp,
+ pf_pool_limits[PF_LIMIT_STATES].limit);
+
+ RB_INIT(&tree_lan_ext);
+ RB_INIT(&tree_ext_gwy);
+ TAILQ_INIT(&pf_anchors);
+ pf_init_ruleset(&pf_main_ruleset);
+ TAILQ_INIT(&pf_altqs[0]);
+ TAILQ_INIT(&pf_altqs[1]);
+ TAILQ_INIT(&pf_pabuf);
+ pf_altqs_active = &pf_altqs[0];
+ pf_altqs_inactive = &pf_altqs[1];
+
+ /* default rule should never be garbage collected */
+ pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
+ pf_default_rule.action = PF_PASS;
+ pf_default_rule.nr = -1;
+
+ /* initialize default timeouts */
+ my_timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */
+ my_timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
+ my_timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */
+ my_timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */
+ my_timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */
+ my_timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */
+ my_timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */
+ my_timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */
+ my_timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */
+ my_timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */
+ my_timeout[PFTM_ICMP_ERROR_REPLY] = 10; /* Got error response */
+ my_timeout[PFTM_OTHER_FIRST_PACKET] = 60; /* First packet */
+ my_timeout[PFTM_OTHER_SINGLE] = 30; /* Unidirectional */
+ my_timeout[PFTM_OTHER_MULTIPLE] = 60; /* Bidirectional */
+ my_timeout[PFTM_FRAG] = 30; /* Fragment expire */
+ my_timeout[PFTM_INTERVAL] = 10; /* Expire interval */
+
+ /*
+ * XXX
+ * The 2nd arg. 0 to callout_init(9) shoule be set to CALLOUT_MPSAFE
+ * if Gaint lock is removed from the network stack.
+ */
+ callout_init(&pf_expire_to, 0);
+ callout_reset(&pf_expire_to, my_timeout[PFTM_INTERVAL] * hz,
+ pf_purge_timeout, &pf_expire_to);
+
+ pf_normalize_init();
+ pf_status.debug = PF_DEBUG_URGENT;
+ pf_pfil_hooked = 0;
+ return (error);
+}
+#else /* !__FreeBSD__ */
void
pfattach(int num)
{
@@ -129,7 +411,7 @@ pfattach(int num)
/* initialize default timeouts */
timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */
- timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
+ timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */
timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */
timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */
@@ -151,7 +433,9 @@ pfattach(int num)
pf_normalize_init();
pf_status.debug = PF_DEBUG_URGENT;
}
+#endif /* __FreeBSD__ */
+#if !defined(__FreeBSD__)
int
pfopen(dev_t dev, int flags, int fmt, struct proc *p)
{
@@ -159,7 +443,9 @@ pfopen(dev_t dev, int flags, int fmt, struct proc *p)
return (ENXIO);
return (0);
}
+#endif
+#if !defined(__FreeBSD__)
int
pfclose(dev_t dev, int flags, int fmt, struct proc *p)
{
@@ -167,6 +453,7 @@ pfclose(dev_t dev, int flags, int fmt, struct proc *p)
return (ENXIO);
return (0);
}
+#endif
struct pf_pool *
pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket,
@@ -349,7 +636,8 @@ pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
struct pf_anchor *anchor;
int i;
- if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 || ruleset->topen)
+ if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 ||
+ ruleset->topen)
return;
for (i = 0; i < PF_RULESET_MAX; ++i)
if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
@@ -498,8 +786,13 @@ pf_tag_unref(u_int16_t tag)
}
}
+#if defined(__FreeBSD__)
+int
+pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
+#else
int
pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
+#endif
{
struct pf_pooladdr *pa = NULL;
struct pf_pool *pool = NULL;
@@ -542,6 +835,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCRCLRASTATS:
case DIOCRTSTADDRS:
case DIOCOSFPGET:
+#if defined(__FreeBSD__)
+ case DIOCGIFSPEED:
+#endif
break;
default:
return (EPERM);
@@ -571,11 +867,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCRGETASTATS:
case DIOCRTSTADDRS:
case DIOCOSFPGET:
+#if defined(__FreeBSD__)
+ case DIOCGIFSPEED:
+#endif
break;
default:
return (EACCES);
}
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
+
switch (cmd) {
case DIOCSTART:
@@ -583,13 +886,32 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EEXIST;
else {
u_int32_t states = pf_status.states;
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+ error = hook_pf();
+ PF_LOCK();
+ if (error) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: pfil registeration fail\n"));
+ break;
+ }
+#endif
bzero(&pf_status, sizeof(struct pf_status));
pf_status.running = 1;
pf_status.states = states;
+#if defined(__FreeBSD__)
+ pf_status.since = time_second;
+#else
pf_status.since = time.tv_sec;
+#endif
if (status_ifp != NULL)
+#if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
+ snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
+ status_ifp->if_name, status_ifp->if_unit);
+#else
strlcpy(pf_status.ifname,
status_ifp->if_xname, IFNAMSIZ);
+#endif
DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
}
break;
@@ -599,6 +921,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = ENOENT;
else {
pf_status.running = 0;
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+ error = dehook_pf();
+ PF_LOCK();
+ if (error) {
+ pf_status.running = 1;
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: pfil unregisteration failed\n"));
+ }
+#endif
DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
}
break;
@@ -1108,7 +1440,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
state->nat_rule.ptr = NULL;
state->anchor.ptr = NULL;
state->rt_ifp = NULL;
+#if defined(__FreeBSD__)
+ state->creation = time_second;
+#else
state->creation = time.tv_sec;
+#endif
state->packets[0] = state->packets[1] = 0;
state->bytes[0] = state->bytes[1] = 0;
if (pf_insert_state(state)) {
@@ -1144,8 +1480,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
-1 : n->state->anchor.ptr->nr;
splx(s);
ps->state.expire = pf_state_expires(n->state);
+#if defined(__FreeBSD__)
+ if (ps->state.expire > time_second)
+ ps->state.expire -= time_second;
+#else
if (ps->state.expire > time.tv_sec)
ps->state.expire -= time.tv_sec;
+#endif
else
ps->state.expire = 0;
break;
@@ -1164,13 +1505,20 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
nr++;
splx(s);
ps->ps_len = sizeof(struct pf_state) * nr;
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
return (0);
}
s = splsoftnet();
p = ps->ps_states;
RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
+#if defined(__FreeBSD__)
+ int secs = time_second;
+#else
int secs = time.tv_sec;
+#endif
if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len)
break;
@@ -1187,7 +1535,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pstore.expire -= secs;
else
pstore.expire = 0;
+#if defined(__FreeBSD__)
+ PF_COPYOUT(&pstore, p, sizeof(*p), error);
+#else
error = copyout(&pstore, p, sizeof(*p));
+#endif
if (error) {
splx(s);
goto fail;
@@ -1236,8 +1588,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pf_status.since = since;
pf_status.debug = debug;
if (status_ifp != NULL)
+#if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
+ snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
+ status_ifp->if_name, status_ifp->if_unit);
+#else
strlcpy(pf_status.ifname,
status_ifp->if_xname, IFNAMSIZ);
+#endif
break;
}
@@ -1339,11 +1696,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EINVAL;
goto fail;
}
+#if defined(__FreeBSD__)
+ uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit);
+#else
if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
pl->limit, NULL, 0) != 0) {
error = EBUSY;
goto fail;
}
+#endif
old_limit = pf_pool_limits[pl->index].limit;
pf_pool_limits[pl->index].limit = pl->limit;
pl->limit = old_limit;
@@ -1370,6 +1731,26 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
+#if defined(__FreeBSD__)
+ case DIOCGIFSPEED: {
+ struct pf_ifspeed *psp = (struct pf_ifspeed *)addr;
+ struct pf_ifspeed ps;
+ struct ifnet *ifp;
+
+ if (psp->ifname[0] != 0) {
+ /* Can we completely trust user-land? */
+ strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
+ ifp = ifunit(ps.ifname);
+ if (ifp )
+ psp->baudrate = ifp->if_baudrate;
+ else
+ error = EINVAL;
+ } else
+ error = EINVAL;
+ break;
+ }
+#endif /* __FreeBSD__ */
+
#ifdef ALTQ
case DIOCSTARTALTQ: {
struct pf_altq *altq;
@@ -1396,8 +1777,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
}
+#if defined(__FreeBSD__)
+ if (error == 0) {
+ mtx_lock(&pf_altq_mtx);
+ pfaltq_running = 1;
+ mtx_unlock(&pf_altq_mtx);
+ }
+#else
if (error == 0)
pfaltq_running = 1;
+#endif
splx(s);
DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
break;
@@ -1429,8 +1818,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = err;
}
}
+#if defined(__FreeBSD__)
+ if (error == 0) {
+ mtx_lock(&pf_altq_mtx);
+ pfaltq_running = 0;
+ mtx_unlock(&pf_altq_mtx);
+ }
+#else
if (error == 0)
pfaltq_running = 0;
+#endif
splx(s);
DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
break;
@@ -1445,7 +1842,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
if (altq->qname[0] == 0) {
/* detach and destroy the discipline */
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
error = altq_remove(altq);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
}
pool_put(&pf_altq_pl, altq);
}
@@ -1482,7 +1885,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
}
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
error = altq_add(altq);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
if (error) {
pool_put(&pf_altq_pl, altq);
break;
@@ -1517,7 +1926,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_FOREACH(altq, pf_altqs_active, entries) {
if (altq->qname[0] == 0) {
/* attach the discipline */
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
error = altq_pfattach(altq);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
if (error) {
splx(s);
goto fail;
@@ -1530,12 +1945,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
if (altq->qname[0] == 0) {
/* detach and destroy the discipline */
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
err = altq_pfdetach(altq);
if (err != 0 && error == 0)
error = err;
err = altq_remove(altq);
if (err != 0 && error == 0)
error = err;
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
}
pool_put(&pf_altq_pl, altq);
}
@@ -1621,7 +2042,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
splx(s);
break;
}
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
error = altq_getqstats(altq, pq->buf, &nbytes);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
splx(s);
if (error == 0) {
pq->scheduler = altq->scheduler;
@@ -2153,6 +2580,713 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
fail:
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
+ return (error);
+}
+
+#if defined(__FreeBSD__)
+/*
+ * XXX - Check for version missmatch!!!
+ */
+static int
+pf_beginrules(void *addr)
+{
+ struct pfioc_rule *pr = (struct pfioc_rule *)addr;
+ struct pf_ruleset *ruleset;
+ struct pf_rule *rule;
+ int rs_num;
+ int error = 0;
+
+ do {
+ ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset);
+ if (ruleset == NULL) {
+ error = EINVAL;
+ break;
+ }
+ rs_num = pf_get_ruleset_number(pr->rule.action);
+ if (rs_num >= PF_RULESET_MAX) {
+ error = EINVAL;
+ break;
+ }
+ while ((rule =
+ TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr)) != NULL)
+ pf_rm_rule(ruleset->rules[rs_num].inactive.ptr, rule);
+ pr->ticket = ++ruleset->rules[rs_num].inactive.ticket;
+ } while(0);
+
+ return (error);
+}
+
+static int
+pf_commitrules(void *addr)
+{
+ struct pfioc_rule *pr = (struct pfioc_rule *)addr;
+ struct pf_ruleset *ruleset;
+ struct pf_rulequeue *old_rules;
+ struct pf_rule *rule;
+ int rs_num, s;
+ int error = 0;
+
+ do {
+ ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);
+ if (ruleset == NULL) {
+ error = EINVAL;
+ break;
+ }
+ rs_num = pf_get_ruleset_number(pr->rule.action);
+ if (rs_num >= PF_RULESET_MAX) {
+ error = EINVAL;
+ break;
+ }
+ if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
+ error = EBUSY;
+ break;
+ }
+
+#ifdef ALTQ
+ /* set queue IDs */
+ if (rs_num == PF_RULESET_FILTER)
+ pf_rule_set_qid(ruleset->rules[rs_num].inactive.ptr);
+#endif
+
+ /* Swap rules, keep the old. */
+ s = splsoftnet();
+ old_rules = ruleset->rules[rs_num].active.ptr;
+ ruleset->rules[rs_num].active.ptr =
+ ruleset->rules[rs_num].inactive.ptr;
+ ruleset->rules[rs_num].inactive.ptr = old_rules;
+ ruleset->rules[rs_num].active.ticket =
+ ruleset->rules[rs_num].inactive.ticket;
+ pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
+
+ /* Purge the old rule list. */
+ while ((rule = TAILQ_FIRST(old_rules)) != NULL)
+ pf_rm_rule(old_rules, rule);
+ pf_remove_if_empty_ruleset(ruleset);
+ pf_update_anchor_rules();
+ splx(s);
+ } while (0);
+
+ return (error);
+}
+
+#if defined(ALTQ)
+static int
+pf_beginaltqs(void *addr)
+{
+ u_int32_t *ticket = (u_int32_t *)addr;
+ struct pf_altq *altq;
+ int error = 0;
+
+ /* Purge the old altq list */
+ while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
+ TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
+ if (altq->qname[0] == 0) {
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
+ /* detach and destroy the discipline */
+ error = altq_remove(altq);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
+ }
+ uma_zfree(pf_altq_pl, altq);
+ }
+ *ticket = ++ticket_altqs_inactive;
return (error);
}
+
+static int
+pf_commitaltqs(void *addr)
+{
+ u_int32_t *ticket = (u_int32_t *)addr;
+ struct pf_altqqueue *old_altqs;
+ struct pf_altq *altq;
+ struct pf_anchor *anchor;
+ struct pf_ruleset *ruleset;
+ int err;
+ int s;
+ int error = 0;
+
+ do {
+ if (*ticket != ticket_altqs_inactive) {
+ error = EBUSY;
+ break;
+ }
+
+ /* Swap altqs, keep the old. */
+ s = splsoftnet();
+ old_altqs = pf_altqs_active;
+ pf_altqs_active = pf_altqs_inactive;
+ pf_altqs_inactive = old_altqs;
+ ticket_altqs_active = ticket_altqs_inactive;
+
+ /* Attach new disciplines */
+ TAILQ_FOREACH(altq, pf_altqs_active, entries) {
+ if (altq->qname[0] == 0) {
+ /* attach the discipline */
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
+ error = altq_pfattach(altq);
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
+ if (error) {
+ splx(s);
+ goto altq_fail;
+ }
+ }
+ }
+
+ /* Purge the old altq list */
+ while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
+ TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
+ if (altq->qname[0] == 0) {
+ /* detach and destroy the discipline */
+#if defined(__FreeBSD__)
+ PF_UNLOCK();
+#endif
+ err = altq_pfdetach(altq);
+ if (err != 0 && error == 0)
+ error = err;
+ err = altq_remove(altq);
+ if (err != 0 && error == 0)
+ error = err;
+#if defined(__FreeBSD__)
+ PF_LOCK();
+#endif
+ }
+ uma_zfree(pf_altq_pl, altq);
+ }
+ splx(s);
+
+ /* update queue IDs */
+ pf_rule_set_qid(
+ pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
+ TAILQ_FOREACH(anchor, &pf_anchors, entries) {
+ TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) {
+ pf_rule_set_qid(
+ ruleset->rules[PF_RULESET_FILTER].active.ptr
+ );
+ }
+ }
+ } while (0);
+
+altq_fail:
+
+ return (error);
+}
+
+static int
+pf_stopaltq(void)
+{
+ struct pf_altq *altq;
+ struct ifnet *ifp;
+ struct tb_profile tb;
+ int err;
+ int s;
+ int error = 0;
+
+ do {
+ /* disable all altq interfaces on active list */
+ s = splsoftnet();
+ TAILQ_FOREACH(altq, pf_altqs_active, entries) {
+ if (altq->qname[0] == 0) {
+ if ((ifp = ifunit(altq->ifname)) == NULL) {
+ error = EINVAL;
+ break;
+ }
+ if (ifp->if_snd.altq_type != ALTQT_NONE) {
+ err = altq_disable(&ifp->if_snd);
+ if (err != 0 && error == 0)
+ error = err;
+ }
+ /* clear tokenbucket regulator */
+ tb.rate = 0;
+ err = tbr_set(&ifp->if_snd, &tb);
+ if (err != 0 && error == 0)
+ error = err;
+ }
+ }
+#if defined(__FreeBSD__)
+ if (error == 0) {
+ mtx_lock(&pf_altq_mtx);
+ pfaltq_running = 0;
+ mtx_unlock(&pf_altq_mtx);
+ }
+#else
+ if (error == 0)
+ pfaltq_running = 0;
+#endif
+ splx(s);
+ } while (0);
+
+ return (error);
+}
+#endif
+
+static void
+pf_clearstates(void)
+{
+ struct pf_tree_node *n;
+ int s;
+
+ s = splsoftnet();
+ RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
+ n->state->timeout = PFTM_PURGE;
+ pf_purge_expired_states();
+ pf_status.states = 0;
+ splx(s);
+}
+
+static int
+pf_clear_tables(void *addr)
+{
+ struct pfioc_table *io = (struct pfioc_table *)addr;
+ int error;
+
+ error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
+ io->pfrio_flags);
+
+ return (error);
+}
+
+static int
+shutdown_pf(void)
+{
+ struct pfioc_rule pr;
+#if defined(ALTQ)
+ struct pfioc_altq pa;
+#endif
+ struct pfioc_table io;
+ int error = 0;
+
+ callout_stop(&pf_expire_to);
+
+ PF_LOCK();
+ pf_status.running = 0;
+ do {
+#if defined(ALTQ)
+ if ((error = pf_stopaltq())) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("ALTQ: stop(%i)\n", error));
+ break;
+ }
+#endif
+ bzero(&pr, sizeof(pr));
+ pr.rule.action = PF_SCRUB;
+ if ((error = pf_beginrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_SCRUB: begin(%i)\n", error));
+ break;
+ }
+ if ((error = pf_commitrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_SCRUB: commit(%i)\n", error));
+ break;
+ }
+
+ pr.rule.action = PF_PASS;
+ if ((error = pf_beginrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_PASS: begin(%i)\n", error));
+ break;
+ }
+ if ((error = pf_commitrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_PASS: commit(%i)\n", error));
+ break;
+ }
+
+/*
+ * XXX not sure, but can't hurt:
+ */
+ bzero(&pr, sizeof(pr));
+ pr.rule.action = PF_NAT;
+ if ((error = pf_beginrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_NAT: begin(%i)\n", error));
+ break;
+ }
+ if ((error = pf_commitrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_NAT: commit(%i)\n", error));
+ break;
+ }
+
+ pr.rule.action = PF_BINAT;
+ if ((error = pf_beginrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_BINAT: begin(%i)\n", error));
+ break;
+ }
+ if ((error = pf_commitrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_BINAT: begin(%i)\n", error));
+ break;
+ }
+
+ pr.rule.action = PF_RDR;
+ if ((error = pf_beginrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_RDR: begin(%i)\n", error));
+ break;
+ }
+ if ((error = pf_commitrules(&pr))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("PF_RDR: commit(%i)\n", error));
+ break;
+ }
+
+#if defined(ALTQ)
+ bzero(&pa, sizeof(pa));
+ if ((error = pf_beginaltqs(&pa))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("ALTQ: begin(%i)\n", error));
+ break;
+ }
+ if ((error = pf_commitaltqs(&pa))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("ALTQ: commit(%i)\n", error));
+ break;
+ }
+#endif
+ pf_clearstates();
+
+ bzero(&io, sizeof(io));
+ if ((error = pf_clear_tables(&io))) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("TABLES: clear(%i)\n", error));
+ break;
+ }
+ pf_osfp_flush();
+ } while(0);
+
+ PF_UNLOCK();
+ return (error);
+}
+
+static int
+#if (__FreeBSD_version < 501108)
+pf_check_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
+#else
+pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
+#endif
+{
+ /*
+ * XXX Wed Jul 9 22:03:16 2003 UTC
+ * OpenBSD has changed its byte ordering convention on ip_len/ip_off
+ * in network stack. OpenBSD's network stack have converted
+ * ip_len/ip_off to host byte order frist as FreeBSD.
+ * Now this is not true anymore , so we should convert back to network
+ * byte order.
+ */
+ struct ip *h = NULL;
+ int chk;
+
+ if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) {
+ /* if m_pkthdr.len is less than ip header, pf will handle. */
+ h = mtod(*m, struct ip *);
+ HTONS(h->ip_len);
+ HTONS(h->ip_off);
+ }
+ chk = pf_test(PF_IN, ifp, m);
+ if (chk && *m) {
+ m_freem(*m);
+ *m = NULL;
+ }
+ if (*m != NULL) {
+ /* pf_test can change ip header location */
+ h = mtod(*m, struct ip *);
+ NTOHS(h->ip_len);
+ NTOHS(h->ip_off);
+ }
+ return chk;
+}
+
+static int
+#if (__FreeBSD_version < 501108)
+pf_check_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
+#else
+pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
+#endif
+{
+ /*
+ * XXX Wed Jul 9 22:03:16 2003 UTC
+ * OpenBSD has changed its byte ordering convention on ip_len/ip_off
+ * in network stack. OpenBSD's network stack have converted
+ * ip_len/ip_off to host byte order frist as FreeBSD.
+ * Now this is not true anymore , so we should convert back to network
+ * byte order.
+ */
+ struct ip *h = NULL;
+ int chk;
+
+ /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
+ if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+ in_delayed_cksum(*m);
+ (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
+ }
+ if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) {
+ /* if m_pkthdr.len is less than ip header, pf will handle. */
+ h = mtod(*m, struct ip *);
+ HTONS(h->ip_len);
+ HTONS(h->ip_off);
+ }
+ chk = pf_test(PF_OUT, ifp, m);
+ if (chk && *m) {
+ m_freem(*m);
+ *m = NULL;
+ }
+ if (*m != NULL) {
+ /* pf_test can change ip header location */
+ h = mtod(*m, struct ip *);
+ NTOHS(h->ip_len);
+ NTOHS(h->ip_off);
+ }
+ return chk;
+}
+
+#ifdef INET6
+static int
+#if (__FreeBSD_version < 501108)
+pf_check6_in(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
+#else
+pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
+#endif
+{
+ /*
+ * IPv6 does not affected ip_len/ip_off byte order changes.
+ */
+ int chk;
+
+ chk = pf_test6(PF_IN, ifp, m);
+ if (chk && *m) {
+ m_freem(*m);
+ *m = NULL;
+ }
+ return chk;
+}
+
+static int
+#if (__FreeBSD_version < 501108)
+pf_check6_out(void *ip, int hlen, struct ifnet *ifp, int dir, struct mbuf **m)
+#else
+pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir)
+#endif
+{
+ /*
+ * IPv6 does not affected ip_len/ip_off byte order changes.
+ */
+ int chk;
+
+ /* We need a proper CSUM befor we start (s. OpenBSD ip_output) */
+ if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
+ in_delayed_cksum(*m);
+ (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
+ }
+ chk = pf_test6(PF_OUT, ifp, m);
+ if (chk && *m) {
+ m_freem(*m);
+ *m = NULL;
+ }
+ return chk;
+}
+#endif /* INET6 */
+
+static int
+hook_pf(void)
+{
+#if (__FreeBSD_version >= 501108)
+ struct pfil_head *pfh_inet;
+#if defined(INET6)
+ struct pfil_head *pfh_inet6;
+#endif
+#endif
+
+ PF_ASSERT(MA_NOTOWNED);
+
+ if (pf_pfil_hooked)
+ return (0);
+
+#if (__FreeBSD_version < 501108)
+ /*
+ * XXX
+ * There is no easy way to get pfil header pointer with address
+ * family such as AF_INET, AF_INET6.
+ * Needs direct variable reference.
+ */
+
+ pfil_add_hook(pf_check_in, PFIL_IN,
+ &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+ pfil_add_hook(pf_check_out, PFIL_OUT,
+ &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+#if defined(INET6)
+ pfil_add_hook(pf_check6_in, PFIL_IN,
+ &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
+ pfil_add_hook(pf_check6_out, PFIL_OUT,
+ &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
+#endif
+#else /* __FreeBSD_version >= 501108 */
+ pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+ if (pfh_inet == NULL)
+ return (ESRCH); /* XXX */
+ pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
+ pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
+#if defined(INET6)
+ pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
+ if (pfh_inet6 == NULL) {
+ pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfh_inet);
+ pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+ pfh_inet);
+ return (ESRCH); /* XXX */
+ }
+ pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
+ pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
+#endif
+#endif /* __FreeBSD_version >= 501108 */
+
+ pf_pfil_hooked = 1;
+ return (0);
+}
+
+static int
+dehook_pf(void)
+{
+#if (__FreeBSD_version >= 501108)
+ struct pfil_head *pfh_inet;
+#if defined(INET6)
+ struct pfil_head *pfh_inet6;
+#endif
+#endif
+
+ PF_ASSERT(MA_NOTOWNED);
+
+ if (pf_pfil_hooked == 0)
+ return (0);
+
+#if (__FreeBSD_version < 501108)
+ pfil_remove_hook(pf_check_in, PFIL_IN,
+ &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+ pfil_remove_hook(pf_check_out, PFIL_OUT,
+ &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
+#if defined(INET6)
+ pfil_remove_hook(pf_check6_in, PFIL_IN,
+ &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
+ pfil_remove_hook(pf_check6_out, PFIL_OUT,
+ &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
+#endif
+#else /* __FreeBSD_version >= 501108 */
+ pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+ if (pfh_inet == NULL)
+ return (ESRCH); /* XXX */
+ pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfh_inet);
+ pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK,
+ pfh_inet);
+#if defined(INET6)
+ pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
+ if (pfh_inet6 == NULL)
+ return (ESRCH); /* XXX */
+ pfil_remove_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK,
+ pfh_inet6);
+ pfil_remove_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK,
+ pfh_inet6);
+#endif
+#endif /* __FreeBSD_version >= 501108 */
+
+ pf_pfil_hooked = 0;
+ return (0);
+}
+
+static int
+pf_load(void)
+{
+ init_zone_var();
+ init_pf_mutex();
+ pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME);
+ if (pfattach() < 0) {
+ destroy_dev(pf_dev);
+ destroy_pf_mutex();
+ return (ENOMEM);
+ }
+#if defined(ALTQ)
+ mtx_lock(&pf_altq_mtx);
+ ++pfaltq_ref;
+ mtx_unlock(&pf_altq_mtx);
+#endif
+ printf("pf: $Name: $\n");
+ return (0);
+}
+
+static int
+pf_unload(void)
+{
+ int error = 0;
+
+ PF_LOCK();
+ pf_status.running = 0;
+ PF_UNLOCK();
+ error = dehook_pf();
+ if (error) {
+ /*
+ * Should not happen!
+ * XXX Due to error code ESRCH, kldunload will show
+ * a message like 'No such process'.
+ */
+ printf("%s : pfil unregisteration fail\n", __FUNCTION__);
+ return error;
+ }
+ shutdown_pf();
+ cleanup_pf_zone();
+ pf_osfp_cleanup();
+ destroy_dev(pf_dev);
+#if defined(ALTQ)
+ mtx_lock(&pf_altq_mtx);
+ --pfaltq_ref;
+ mtx_unlock(&pf_altq_mtx);
+#endif
+ destroy_pf_mutex();
+ return error;
+}
+
+static int
+pf_modevent(module_t mod, int type, void *data)
+{
+ int error = 0;
+
+ switch(type) {
+ case MOD_LOAD:
+ error = pf_load();
+ break;
+
+ case MOD_UNLOAD:
+ error = pf_unload();
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return error;
+}
+
+static moduledata_t pf_mod = {
+ "pf",
+ pf_modevent,
+ 0
+};
+
+DECLARE_MODULE(pf, pf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
+MODULE_DEPEND(pf, pflog, PFLOG_MINVER, PFLOG_PREFVER, PFLOG_MAXVER);
+MODULE_DEPEND(pf, pfsync, PFSYNC_MINVER, PFSYNC_PREFVER, PFSYNC_MAXVER);
+#if defined(ALTQ)
+MODULE_DEPEND(pf, pfaltq, PFALTQ_MINVER, PFALTQ_PREFVER, PFALTQ_MAXVER);
+#endif
+MODULE_VERSION(pf, PF_MODVER);
+#endif /* __FreeBSD__ */
diff --git a/sys/contrib/pf/net/pf_norm.c b/sys/contrib/pf/net/pf_norm.c
index 02b81985f2e4..8f597d864980 100644
--- a/sys/contrib/pf/net/pf_norm.c
+++ b/sys/contrib/pf/net/pf_norm.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: pf_norm.c,v 1.75 2003/08/29 01:49:08 dhartmei Exp $ */
/*
@@ -25,7 +26,15 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if defined(__FreeBSD__)
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#include "opt_random_ip_id.h" /* or ip_var does not export it */
+#include "opt_pf.h"
+#define NPFLOG DEV_PFLOG
+#else
#include "pflog.h"
+#endif
#include <sys/param.h>
#include <sys/systm.h>
@@ -35,9 +44,13 @@
#include <sys/socket.h>
#include <sys/kernel.h>
#include <sys/time.h>
+#if !defined(__FreeBSD__)
#include <sys/pool.h>
+#endif
+#if !defined(__FreeBSD__)
#include <dev/rndvar.h>
+#endif
#include <net/if.h>
#include <net/if_types.h>
#include <net/bpf.h>
@@ -60,6 +73,49 @@
#include <net/pfvar.h>
+#if defined(__FreeBSD__) && defined(INET6)
+/*
+ * XXX: This should go to netinet/ip6.h (KAME)
+ */
+/* IPv6 options: common part */
+struct ip6_opt {
+ u_int8_t ip6o_type;
+ u_int8_t ip6o_len;
+} __packed;
+
+/* Jumbo Payload Option */
+struct ip6_opt_jumbo {
+ u_int8_t ip6oj_type;
+ u_int8_t ip6oj_len;
+ u_int8_t ip6oj_jumbo_len[4];
+} __packed;
+
+/* NSAP Address Option */
+struct ip6_opt_nsap {
+ u_int8_t ip6on_type;
+ u_int8_t ip6on_len;
+ u_int8_t ip6on_src_nsap_len;
+ u_int8_t ip6on_dst_nsap_len;
+ /* followed by source NSAP */
+ /* followed by destination NSAP */
+} __packed;
+
+/* Tunnel Limit Option */
+struct ip6_opt_tunnel {
+ u_int8_t ip6ot_type;
+ u_int8_t ip6ot_len;
+ u_int8_t ip6ot_encap_limit;
+} __packed;
+
+/* Router Alert Option */
+struct ip6_opt_router {
+ u_int8_t ip6or_type;
+ u_int8_t ip6or_len;
+ u_int8_t ip6or_value[2];
+} __packed;
+#endif /* __FreeBSD__ && INET6 */
+
+#if !defined(__FreeBSD__)
struct pf_frent {
LIST_ENTRY(pf_frent) fr_next;
struct ip *fr_ip;
@@ -71,12 +127,14 @@ struct pf_frcache {
uint16_t fr_off;
uint16_t fr_end;
};
+#endif
#define PFFRAG_SEENLAST 0x0001 /* Seen the last fragment for this */
#define PFFRAG_NOBUFFER 0x0002 /* Non-buffering fragment cache */
#define PFFRAG_DROP 0x0004 /* Drop all fragments */
#define BUFFER_FRAGMENTS(fr) (!((fr)->fr_flags & PFFRAG_NOBUFFER))
+#if !defined(__FreeBSD__)
struct pf_fragment {
RB_ENTRY(pf_fragment) fr_entry;
TAILQ_ENTRY(pf_fragment) frag_next;
@@ -94,6 +152,7 @@ struct pf_fragment {
LIST_HEAD(pf_cacheq, pf_frcache) fru_cache; /* non-buf */
} fr_u;
};
+#endif
TAILQ_HEAD(pf_fragqueue, pf_fragment) pf_fragqueue;
TAILQ_HEAD(pf_cachequeue, pf_fragment) pf_cachequeue;
@@ -105,6 +164,9 @@ RB_PROTOTYPE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare);
RB_GENERATE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare);
/* Private prototypes */
+#ifndef RANDOM_IP_ID
+extern u_int16_t ip_randomid(void);
+#endif
void pf_ip2key(struct pf_fragment *, struct ip *);
void pf_remove_fragment(struct pf_fragment *);
void pf_flush_fragments(void);
@@ -122,13 +184,28 @@ int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *,
{ printf("%s: ", __func__); printf x ;}
/* Globals */
+#if defined(__FreeBSD__)
+uma_zone_t pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl;
+uma_zone_t pf_state_scrub_pl;
+#else
struct pool pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl;
struct pool pf_state_scrub_pl;
+#endif
int pf_nfrents, pf_ncache;
void
pf_normalize_init(void)
{
+#if defined(__FreeBSD__)
+ /*
+ * XXX
+ * No high water mark support(It's hint not hard limit).
+ * uma_zone_set_max(pf_frag_pl, PFFRAG_FRAG_HIWAT);
+ */
+ uma_zone_set_max(pf_frent_pl, PFFRAG_FRENT_HIWAT);
+ uma_zone_set_max(pf_cache_pl, PFFRAG_FRCACHE_HIWAT);
+ uma_zone_set_max(pf_cent_pl, PFFRAG_FRCENT_HIWAT);
+#else
pool_init(&pf_frent_pl, sizeof(struct pf_frent), 0, 0, 0, "pffrent",
NULL);
pool_init(&pf_frag_pl, sizeof(struct pf_fragment), 0, 0, 0, "pffrag",
@@ -144,6 +221,7 @@ pf_normalize_init(void)
pool_sethardlimit(&pf_frent_pl, PFFRAG_FRENT_HIWAT, NULL, 0);
pool_sethardlimit(&pf_cache_pl, PFFRAG_FRCACHE_HIWAT, NULL, 0);
pool_sethardlimit(&pf_cent_pl, PFFRAG_FRCENT_HIWAT, NULL, 0);
+#endif
TAILQ_INIT(&pf_fragqueue);
TAILQ_INIT(&pf_cachequeue);
@@ -173,11 +251,21 @@ void
pf_purge_expired_fragments(void)
{
struct pf_fragment *frag;
+#if defined(__FreeBSD__)
+ u_int32_t expire = time_second -
+ pf_default_rule.timeout[PFTM_FRAG];
+#else
u_int32_t expire = time.tv_sec -
pf_default_rule.timeout[PFTM_FRAG];
+#endif
while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) {
+#if defined(__FreeBSD__)
+ KASSERT((BUFFER_FRAGMENTS(frag)),
+ ("BUFFER_FRAGMENTS(frag) == 0: %s", __FUNCTION__));
+#else
KASSERT(BUFFER_FRAGMENTS(frag));
+#endif
if (frag->fr_timeout > expire)
break;
@@ -186,14 +274,26 @@ pf_purge_expired_fragments(void)
}
while ((frag = TAILQ_LAST(&pf_cachequeue, pf_cachequeue)) != NULL) {
+#if defined(__FreeBSD__)
+ KASSERT((!BUFFER_FRAGMENTS(frag)),
+ ("BUFFER_FRAGMENTS(frag) != 0: %s", __FUNCTION__));
+#else
KASSERT(!BUFFER_FRAGMENTS(frag));
+#endif
if (frag->fr_timeout > expire)
break;
DPFPRINTF(("expiring %d(%p)\n", frag->fr_id, frag));
pf_free_fragment(frag);
+#if defined(__FreeBSD__)
+ KASSERT((TAILQ_EMPTY(&pf_cachequeue) ||
+ TAILQ_LAST(&pf_cachequeue, pf_cachequeue) != frag),
+ ("!(TAILQ_EMPTY() || TAILQ_LAST() == farg): %s",
+ __FUNCTION__));
+#else
KASSERT(TAILQ_EMPTY(&pf_cachequeue) ||
TAILQ_LAST(&pf_cachequeue, pf_cachequeue) != frag);
+#endif
}
}
@@ -252,9 +352,17 @@ pf_free_fragment(struct pf_fragment *frag)
frcache = LIST_FIRST(&frag->fr_cache)) {
LIST_REMOVE(frcache, fr_next);
+#if defined(__FreeBSD__)
+ KASSERT((LIST_EMPTY(&frag->fr_cache) ||
+ LIST_FIRST(&frag->fr_cache)->fr_off >
+ frcache->fr_end),
+ ("! (LIST_EMPTY() || LIST_FIRST()->fr_off >"
+ " frcache->fr_end): %s", __FUNCTION__));
+#else
KASSERT(LIST_EMPTY(&frag->fr_cache) ||
LIST_FIRST(&frag->fr_cache)->fr_off >
frcache->fr_end);
+#endif
pool_put(&pf_cent_pl, frcache);
pf_ncache--;
@@ -284,7 +392,11 @@ pf_find_fragment(struct ip *ip, struct pf_frag_tree *tree)
frag = RB_FIND(pf_frag_tree, tree, &key);
if (frag != NULL) {
/* XXX Are we sure we want to update the timeout? */
+#if defined(__FreeBSD__)
+ frag->fr_timeout = time_second;
+#else
frag->fr_timeout = time.tv_sec;
+#endif
if (BUFFER_FRAGMENTS(frag)) {
TAILQ_REMOVE(&pf_fragqueue, frag, frag_next);
TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next);
@@ -327,7 +439,12 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
u_int16_t ip_len = ntohs(ip->ip_len) - ip->ip_hl * 4;
u_int16_t max = ip_len + off;
+#if defined(__FreeBSD__)
+ KASSERT((*frag == NULL || BUFFER_FRAGMENTS(*frag)),
+ ("! (*frag == NULL || BUFFER_FRAGMENTS(*frag)): %s", __FUNCTION__));
+#else
KASSERT(*frag == NULL || BUFFER_FRAGMENTS(*frag));
+#endif
/* Strip off ip header */
m->m_data += hlen;
@@ -349,7 +466,11 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
(*frag)->fr_dst = frent->fr_ip->ip_dst;
(*frag)->fr_p = frent->fr_ip->ip_p;
(*frag)->fr_id = frent->fr_ip->ip_id;
+#if defined(__FreeBSD__)
+ (*frag)->fr_timeout = time_second;
+#else
(*frag)->fr_timeout = time.tv_sec;
+#endif
LIST_INIT(&(*frag)->fr_queue);
RB_INSERT(pf_frag_tree, &pf_frag_tree, *frag);
@@ -370,7 +491,12 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
frep = frea;
}
+#if defined(__FreeBSD__)
+ KASSERT((frep != NULL || frea != NULL),
+ ("!(frep != NULL || frea != NULL): %s", __FUNCTION__));;
+#else
KASSERT(frep != NULL || frea != NULL);
+#endif
if (frep != NULL &&
FR_IP_OFF(frep) + ntohs(frep->fr_ip->ip_len) - frep->fr_ip->ip_hl *
@@ -455,7 +581,11 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag,
/* We have all the data */
frent = LIST_FIRST(&(*frag)->fr_queue);
+#if defined(__FreeBSD__)
+ KASSERT((frent != NULL), ("frent == NULL: %s", __FUNCTION__));
+#else
KASSERT(frent != NULL);
+#endif
if ((frent->fr_ip->ip_hl << 2) + off > IP_MAXPACKET) {
DPFPRINTF(("drop: too big: %d\n", off));
pf_free_fragment(*frag);
@@ -524,7 +654,12 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
u_int16_t max = ip_len + off;
int hosed = 0;
+#if defined(__FreeBSD__)
+ KASSERT((*frag == NULL || !BUFFER_FRAGMENTS(*frag)),
+ ("!(*frag == NULL || !BUFFER_FRAGMENTS(*frag)): %s", __FUNCTION__));
+#else
KASSERT(*frag == NULL || !BUFFER_FRAGMENTS(*frag));
+#endif
/* Create a new range queue for this packet */
if (*frag == NULL) {
@@ -551,7 +686,11 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
(*frag)->fr_dst = h->ip_dst;
(*frag)->fr_p = h->ip_p;
(*frag)->fr_id = h->ip_id;
+#if defined(__FreeBSD__)
+ (*frag)->fr_timeout = time_second;
+#else
(*frag)->fr_timeout = time.tv_sec;
+#endif
cur->fr_off = off;
cur->fr_end = max;
@@ -577,7 +716,12 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
frp = fra;
}
+#if defined(__FreeBSD__)
+ KASSERT((frp != NULL || fra != NULL),
+ ("!(frp != NULL || fra != NULL): %s", __FUNCTION__));
+#else
KASSERT(frp != NULL || fra != NULL);
+#endif
if (frp != NULL) {
int precut;
@@ -619,10 +763,23 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
* than this mbuf magic. For my next trick,
* I'll pull a rabbit out of my laptop.
*/
+#if defined(__FreeBSD__)
+ *m0 = m_dup(m, M_DONTWAIT);
+ /* From KAME Project : We have missed this! */
+ m_adj(*m0, (h->ip_hl << 2) -
+ (*m0)->m_pkthdr.len);
+#else
*m0 = m_copym2(m, 0, h->ip_hl << 2, M_NOWAIT);
+#endif
if (*m0 == NULL)
goto no_mem;
+#if defined(__FreeBSD__)
+ KASSERT(((*m0)->m_next == NULL),
+ ("(*m0)->m_next != NULL: %s",
+ __FUNCTION__));
+#else
KASSERT((*m0)->m_next == NULL);
+#endif
m_adj(m, precut + (h->ip_hl << 2));
m_cat(*m0, m);
m = *m0;
@@ -637,8 +794,13 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
h = mtod(m, struct ip *);
-
+#if defined(__FreeBSD__)
+ KASSERT(((int)m->m_len == ntohs(h->ip_len) - precut),
+ ("m->m_len != ntohs(h->ip_len) - precut: %s",
+ __FUNCTION__));
+#else
KASSERT((int)m->m_len == ntohs(h->ip_len) - precut);
+#endif
h->ip_off = htons(ntohs(h->ip_off) + (precut >> 3));
h->ip_len = htons(ntohs(h->ip_len) - precut);
} else {
@@ -693,7 +855,13 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
m->m_pkthdr.len = plen;
}
h = mtod(m, struct ip *);
+#if defined(__FreeBSD__)
+ KASSERT(((int)m->m_len == ntohs(h->ip_len) - aftercut),
+ ("m->m_len != ntohs(h->ip_len) - aftercut: %s",
+ __FUNCTION__));
+#else
KASSERT((int)m->m_len == ntohs(h->ip_len) - aftercut);
+#endif
h->ip_len = htons(ntohs(h->ip_len) - aftercut);
} else {
hosed++;
@@ -731,7 +899,12 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff,
} else if (frp && fra->fr_off <= frp->fr_end) {
/* Need to merge in a modified 'frp' */
+#if defined(__FreeBSD__)
+ KASSERT((cur == NULL), ("cur != NULL: %s",
+ __FUNCTION__));
+#else
KASSERT(cur == NULL);
+#endif
DPFPRINTF(("fragcache[%d]: adjacent(merge "
"%d-%d) %d-%d (%d-%d)\n",
h->ip_id, frp->fr_off, frp->fr_end, off,
@@ -1283,7 +1456,7 @@ pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff,
/* copy back packet headers if we sanitized */
if (rewrite)
- m_copyback(m, off, sizeof(*th), th);
+ m_copyback(m, off, sizeof(*th), (caddr_t)th);
return (PF_PASS);
@@ -1301,7 +1474,12 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd,
u_int8_t hdr[60];
u_int8_t *opt;
+#if defined(__FreeBSD__)
+ KASSERT((src->scrub == NULL),
+ ("pf_normalize_tcp_init: src->scrub != NULL"));
+#else
KASSERT(src->scrub == NULL);
+#endif
src->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT);
if (src->scrub == NULL)
@@ -1385,7 +1563,12 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,
u_int8_t *opt;
int copyback = 0;
+#if defined(__FreeBSD__)
+ KASSERT((src->scrub || dst->scrub),
+ ("pf_normalize_tcp_statefull: src->scrub && dst->scrub!"));
+#else
KASSERT(src->scrub || dst->scrub);
+#endif
/*
* Enforce the minimum TTL seen for this connection. Negate a common
diff --git a/sys/contrib/pf/net/pf_osfp.c b/sys/contrib/pf/net/pf_osfp.c
index c01d6de64078..45d0c10d5f41 100644
--- a/sys/contrib/pf/net/pf_osfp.c
+++ b/sys/contrib/pf/net/pf_osfp.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: pf_osfp.c,v 1.3 2003/08/27 18:23:36 frantzen Exp $ */
/*
@@ -36,12 +37,15 @@
#include <netinet/ip6.h>
#endif /* INET6 */
-
#ifdef _KERNEL
# define DPFPRINTF(format, x...) \
if (pf_status.debug >= PF_DEBUG_NOISY) \
printf(format , ##x)
+#if defined(__FreeBSD__)
+typedef uma_zone_t pool_t;
+#else
typedef struct pool pool_t;
+#endif
#else
/* Userland equivalents so we can lend code to tcpdump et al. */
@@ -55,6 +59,10 @@ typedef struct pool pool_t;
# define pool_put(pool, item) free(item)
# define pool_init(pool, size, a, ao, f, m, p) (*(pool)) = (size)
+# if defined(__FreeBSD__)
+# define NTOHS(x) (x) = ntohs((u_int16_t)(x))
+# endif
+
# ifdef PFDEBUG
# include <stdarg.h>
# define DPFPRINTF(format, x...) fprintf(stderr, format , ##x)
@@ -106,7 +114,7 @@ pf_osfp_fingerprint_hdr(const struct ip *ip, const struct tcphdr *tcp)
{
struct pf_os_fingerprint fp, *fpresult;
int cnt, optlen = 0;
- u_int8_t *optp;
+ const u_int8_t *optp;
if ((tcp->th_flags & (TH_SYN|TH_ACK)) != TH_SYN || (ip->ip_off &
htons(IP_OFFMASK)))
@@ -122,7 +130,7 @@ pf_osfp_fingerprint_hdr(const struct ip *ip, const struct tcphdr *tcp)
cnt = (tcp->th_off << 2) - sizeof(*tcp);
- optp = (caddr_t)tcp + sizeof(*tcp);
+ optp = (const u_int8_t *)((const char *)tcp + sizeof(*tcp));
for (; cnt > 0; cnt -= optlen, optp += optlen) {
if (*optp == TCPOPT_EOL)
break;
@@ -228,15 +236,46 @@ pf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os)
}
/* Initialize the OS fingerprint system */
+#if defined(__FreeBSD__)
+int
+#else
void
+#endif
pf_osfp_initialize(void)
{
+#if defined(__FreeBSD__) && defined(_KERNEL)
+ int error = ENOMEM;
+
+ do {
+ pf_osfp_entry_pl = pf_osfp_pl = NULL;
+ UMA_CREATE(pf_osfp_entry_pl, struct pf_osfp_entry, "pfospfen");
+ UMA_CREATE(pf_osfp_pl, struct pf_os_fingerprint, "pfosfp");
+ error = 0;
+ } while(0);
+#else
pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0,
"pfosfpen", NULL);
pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0,
"pfosfp", NULL);
+#endif
SLIST_INIT(&pf_osfp_list);
+#if defined(__FreeBSD__)
+#if defined(_KERNEL)
+ return (error);
+#else
+ return (0);
+#endif
+#endif
+}
+
+#if defined(__FreeBSD__) && (_KERNEL)
+void
+pf_osfp_cleanup(void)
+{
+ UMA_DESTROY(pf_osfp_entry_pl);
+ UMA_DESTROY(pf_osfp_pl);
}
+#endif
/* Flush the fingerprint list */
void
diff --git a/sys/contrib/pf/net/pf_table.c b/sys/contrib/pf/net/pf_table.c
index e6ce25fa46e0..c96fd7030f61 100644
--- a/sys/contrib/pf/net/pf_table.c
+++ b/sys/contrib/pf/net/pf_table.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: pf_table.c,v 1.41 2003/08/22 15:19:23 henning Exp $ */
/*
@@ -30,18 +31,33 @@
*
*/
+#if defined(__FreeBSD__)
+#include "opt_inet.h"
+#include "opt_inet6.h"
+#endif
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
+#if defined(__FreeBSD__)
+#include <sys/malloc.h>
+#endif
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
+#if !defined(__FreeBSD__)
#include <netinet/ip_ipsp.h>
+#endif
+
#include <net/pfvar.h>
+#if defined(FreeBSD__)
+MALLOC_DECLARE(M_RTABLE);
+#endif
+
#define ACCEPT_FLAGS(oklist) \
do { \
if ((flags & ~(oklist)) & \
@@ -109,8 +125,13 @@ struct pfr_walktree {
#define senderr(e) do { rv = (e); goto _bad; } while (0)
+#if defined(__FreeBSD__)
+uma_zone_t pfr_ktable_pl;
+uma_zone_t pfr_kentry_pl;
+#else
struct pool pfr_ktable_pl;
struct pool pfr_kentry_pl;
+#endif
struct sockaddr_in pfr_sin;
struct sockaddr_in6 pfr_sin6;
union sockaddr_union pfr_mask;
@@ -155,7 +176,7 @@ void pfr_destroy_ktable(struct pfr_ktable *, int);
int pfr_ktable_compare(struct pfr_ktable *,
struct pfr_ktable *);
struct pfr_ktable *pfr_lookup_table(struct pfr_table *);
-void pfr_clean_node_mask(struct pfr_ktable *,
+void pfr_clean_node_mask(struct pfr_ktable *,
struct pfr_kentryworkq *);
int pfr_table_count(struct pfr_table *, int);
int pfr_skip_table(struct pfr_table *,
@@ -172,10 +193,12 @@ int pfr_ktable_cnt;
void
pfr_initialize(void)
{
+#if !defined(__FreeBSD__)
pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0,
"pfrktable", NULL);
pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0,
"pfrkentry", NULL);
+#endif
pfr_sin.sin_len = sizeof(pfr_sin);
pfr_sin.sin_family = AF_INET;
@@ -226,7 +249,15 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_kentry *p, *q;
struct pfr_addr ad;
int i, rv, s, xadd = 0;
+#if defined(__FreeBSD__)
+ int ec;
+ /*
+ * XXX Is it OK under LP64 environments?
+ */
+ long tzero = (long)time_second;
+#else
long tzero = time.tv_sec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, 0))
@@ -241,8 +272,14 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
return (ENOMEM);
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(addr+i, &ad, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+#else
if (copyin(addr+i, &ad, sizeof(ad)))
senderr(EFAULT);
+#endif
if (pfr_validate_addr(&ad))
senderr(EINVAL);
p = pfr_lookup_addr(kt, &ad, 1);
@@ -269,9 +306,17 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
xadd++;
}
}
+#if defined(__FreeBSD__)
+ if (flags & PFR_FLAG_FEEDBACK) {
+ PF_COPYOUT(&ad, addr+i, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+ }
+#else
if (flags & PFR_FLAG_FEEDBACK)
if (copyout(&ad, addr+i, sizeof(ad)))
senderr(EFAULT);
+#endif
}
pfr_clean_node_mask(tmpkt, &workq);
if (!(flags & PFR_FLAG_DUMMY)) {
@@ -304,6 +349,9 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_kentry *p;
struct pfr_addr ad;
int i, rv, s, xdel = 0;
+#if defined(__FreeBSD__)
+ int ec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, 0))
@@ -316,8 +364,14 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
pfr_mark_addrs(kt);
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(addr+i, &ad, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+#else
if (copyin(addr+i, &ad, sizeof(ad)))
senderr(EFAULT);
+#endif
if (pfr_validate_addr(&ad))
senderr(EINVAL);
p = pfr_lookup_addr(kt, &ad, 1);
@@ -337,9 +391,17 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
xdel++;
}
+#if defined(__FreeBSD__)
+ if (flags & PFR_FLAG_FEEDBACK) {
+ PF_COPYOUT(&ad, addr+i, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+ }
+#else
if (flags & PFR_FLAG_FEEDBACK)
if (copyout(&ad, addr+i, sizeof(ad)))
senderr(EFAULT);
+#endif
}
if (!(flags & PFR_FLAG_DUMMY)) {
if (flags & PFR_FLAG_ATOMIC)
@@ -366,7 +428,15 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_kentry *p, *q;
struct pfr_addr ad;
int i, rv, s, xadd = 0, xdel = 0, xchange = 0;
+#if defined(__FreeBSD__)
+ int ec;
+ /*
+ * XXX Is it OK under LP64 environments?
+ */
+ long tzero = (long)time_second;
+#else
long tzero = time.tv_sec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, 0))
@@ -384,8 +454,14 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
SLIST_INIT(&delq);
SLIST_INIT(&changeq);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(addr+i, &ad, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+#else
if (copyin(addr+i, &ad, sizeof(ad)))
senderr(EFAULT);
+#endif
if (pfr_validate_addr(&ad))
senderr(EINVAL);
ad.pfra_fback = PFR_FB_NONE;
@@ -420,9 +496,17 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
}
}
_skip:
+#if defined(__FreeBSD__)
+ if (flags & PFR_FLAG_FEEDBACK) {
+ PF_COPYOUT(&ad, addr+i, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+ }
+#else
if (flags & PFR_FLAG_FEEDBACK)
if (copyout(&ad, addr+i, sizeof(ad)))
senderr(EFAULT);
+#endif
}
pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);
if ((flags & PFR_FLAG_FEEDBACK) && *size2) {
@@ -434,8 +518,14 @@ _skip:
SLIST_FOREACH(p, &delq, pfrke_workq) {
pfr_copyout_addr(&ad, p);
ad.pfra_fback = PFR_FB_DELETED;
+#if defined(__FreeBSD__)
+ PF_COPYOUT(&ad, addr+size+i, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+#else
if (copyout(&ad, addr+size+i, sizeof(ad)))
senderr(EFAULT);
+#endif
i++;
}
}
@@ -477,6 +567,9 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_kentry *p;
struct pfr_addr ad;
int i, xmatch = 0;
+#if defined(__FreeBSD__)
+ int ec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_REPLACE);
if (pfr_validate_table(tbl, 0))
@@ -486,8 +579,14 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
return (ESRCH);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(addr+i, &ad, sizeof(ad), ec);
+ if (ec)
+ return (EFAULT);
+#else
if (copyin(addr+i, &ad, sizeof(ad)))
return (EFAULT);
+#endif
if (pfr_validate_addr(&ad))
return (EINVAL);
if (ADDR_NETWORK(&ad))
@@ -499,8 +598,14 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
(p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH);
if (p != NULL && !p->pfrke_not)
xmatch++;
+#if defined(__FreeBSD__)
+ PF_COPYOUT(&ad, addr+i, sizeof(ad), ec);
+ if (ec)
+ return (EFAULT);
+#else
if (copyout(&ad, addr+i, sizeof(ad)))
return (EFAULT);
+#endif
}
if (nmatch != NULL)
*nmatch = xmatch;
@@ -530,9 +635,18 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
w.pfrw_op = PFRW_GET_ADDRS;
w.pfrw_addr = addr;
w.pfrw_free = kt->pfrkt_cnt;
+#if defined(__FreeBSD__)
+ rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#else
rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#endif
if (!rv)
+#if defined(__FreeBSD__)
+ rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
+ &w);
+#else
rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#endif
if (rv)
return (rv);
@@ -553,7 +667,14 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
struct pfr_walktree w;
struct pfr_kentryworkq workq;
int rv, s;
+#if defined(__FreeBSD__)
+ /*
+ * XXX Is it OK under LP64 environments?
+ */
+ long tzero = (long)time_second;
+#else
long tzero = time.tv_sec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */
if (pfr_validate_table(tbl, 0))
@@ -572,9 +693,18 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
w.pfrw_free = kt->pfrkt_cnt;
if (flags & PFR_FLAG_ATOMIC)
s = splsoftnet();
+#if defined(__FreeBSD__)
+ rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#else
rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#endif
if (!rv)
+#if defined(__FreeBSD__)
+ rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
+ &w);
+#else
rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#endif
if (!rv && (flags & PFR_FLAG_CLSTATS)) {
pfr_enqueue_addrs(kt, &workq, NULL, 0);
pfr_clstats_kentries(&workq, tzero, 0);
@@ -602,6 +732,9 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_kentry *p;
struct pfr_addr ad;
int i, rv, s, xzero = 0;
+#if defined(__FreeBSD__)
+ int ec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK);
if (pfr_validate_table(tbl, 0))
@@ -611,16 +744,28 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
return (ESRCH);
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(addr+i, &ad, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+#else
if (copyin(addr+i, &ad, sizeof(ad)))
senderr(EFAULT);
+#endif
if (pfr_validate_addr(&ad))
senderr(EINVAL);
p = pfr_lookup_addr(kt, &ad, 1);
if (flags & PFR_FLAG_FEEDBACK) {
ad.pfra_fback = (p != NULL) ?
PFR_FB_CLEARED : PFR_FB_NONE;
+#if defined(__FreeBSD__)
+ PF_COPYOUT(&ad, addr+i, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+#else
if (copyout(&ad, addr+i, sizeof(ad)))
senderr(EFAULT);
+#endif
}
if (p != NULL) {
SLIST_INSERT_HEAD(&workq, p, pfrke_workq);
@@ -685,10 +830,20 @@ pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq,
w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE;
w.pfrw_workq = workq;
if (kt->pfrkt_ip4 != NULL)
+#if defined(__FreeBSD__)
+ if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree,
+ &w))
+#else
if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
+#endif
printf("pfr_enqueue_addrs: IPv4 walktree failed.\n");
if (kt->pfrkt_ip6 != NULL)
+#if defined(__FreeBSD__)
+ if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree,
+ &w))
+#else
if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
+#endif
printf("pfr_enqueue_addrs: IPv6 walktree failed.\n");
if (naddr != NULL)
*naddr = w.pfrw_cnt;
@@ -701,9 +856,17 @@ pfr_mark_addrs(struct pfr_ktable *kt)
bzero(&w, sizeof(w));
w.pfrw_op = PFRW_MARK;
+#if defined(__FreeBSD__)
+ if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
+#else
if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w))
+#endif
printf("pfr_mark_addrs: IPv4 walktree failed.\n");
+#if defined(__FreeBSD__)
+ if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
+#else
if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w))
+#endif
printf("pfr_mark_addrs: IPv6 walktree failed.\n");
}
@@ -727,7 +890,13 @@ pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact)
if (ADDR_NETWORK(ad)) {
pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net);
s = splsoftnet(); /* rn_lookup makes use of globals */
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_LOCK(head);
+#endif
ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head);
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_UNLOCK(head);
+#endif
splx(s);
if (ke && KENTRY_RNF_ROOT(ke))
ke = NULL;
@@ -845,13 +1014,28 @@ pfr_reset_feedback(struct pfr_addr *addr, int size)
{
struct pfr_addr ad;
int i;
+#if defined(__FreeBSD__)
+ int ec;
+#endif
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(addr+i, &ad, sizeof(ad), ec);
+ if (ec)
+ break;
+#else
if (copyin(addr+i, &ad, sizeof(ad)))
break;
+#endif
ad.pfra_fback = PFR_FB_NONE;
+#if defined(__FreeBSD__)
+ PF_COPYOUT(&ad, addr+i, sizeof(ad), ec);
+ if (ec)
+ break;
+#else
if (copyout(&ad, addr+i, sizeof(ad)))
break;
+#endif
}
}
@@ -895,11 +1079,17 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
head = kt->pfrkt_ip6;
s = splsoftnet();
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_LOCK(head);
+#endif
if (KENTRY_NETWORK(ke)) {
pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node);
} else
rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node);
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_UNLOCK(head);
+#endif
splx(s);
return (rn == NULL ? -1 : 0);
@@ -919,11 +1109,17 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke)
head = kt->pfrkt_ip6;
s = splsoftnet();
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_LOCK(head);
+#endif
if (KENTRY_NETWORK(ke)) {
pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net);
rn = rn_delete(&ke->pfrke_sa, &mask, head);
} else
rn = rn_delete(&ke->pfrke_sa, NULL, head);
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ RADIX_NODE_HEAD_UNLOCK(head);
+#endif
splx(s);
if (rn == NULL) {
@@ -954,6 +1150,9 @@ pfr_walktree(struct radix_node *rn, void *arg)
struct pfr_kentry *ke = (struct pfr_kentry *)rn;
struct pfr_walktree *w = arg;
int s;
+#if defined(__FreeBSD__)
+ int ec;
+#endif
switch (w->pfrw_op) {
case PFRW_MARK:
@@ -972,8 +1171,14 @@ pfr_walktree(struct radix_node *rn, void *arg)
struct pfr_addr ad;
pfr_copyout_addr(&ad, ke);
+#if defined(__FreeBSD__)
+ PF_COPYOUT(&ad, w->pfrw_addr, sizeof(ad), ec);
+ if (ec)
+ return (EFAULT);
+#else
if (copyout(&ad, w->pfrw_addr, sizeof(ad)))
return (EFAULT);
+#endif
w->pfrw_addr++;
}
break;
@@ -991,8 +1196,14 @@ pfr_walktree(struct radix_node *rn, void *arg)
splx(s);
as.pfras_tzero = ke->pfrke_tzero;
+#if defined(__FreeBSD__)
+ PF_COPYOUT(&as, w->pfrw_astats, sizeof(as), ec);
+ if (ec)
+ return (EFAULT);
+#else
if (copyout(&as, w->pfrw_astats, sizeof(as)))
return (EFAULT);
+#endif
w->pfrw_astats++;
}
break;
@@ -1047,14 +1258,28 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
struct pfr_ktableworkq addq, changeq;
struct pfr_ktable *p, *q, *r, key;
int i, rv, s, xadd = 0;
+#if defined(__FreeBSD__)
+ int ec;
+ /*
+ * XXX Is it OK under LP64 environments?
+ */
+ long tzero = (long)time_second;
+#else
long tzero = time.tv_sec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
SLIST_INIT(&addq);
SLIST_INIT(&changeq);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), ec);
+ if (ec)
+ senderr(EFAULT);
+#else
if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
senderr(EFAULT);
+#endif
if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK))
senderr(EINVAL);
key.pfrkt_flags |= PFR_TFLAG_ACTIVE;
@@ -1127,12 +1352,21 @@ pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
struct pfr_ktableworkq workq;
struct pfr_ktable *p, *q, key;
int i, s, xdel = 0;
+#if defined(__FreeBSD__)
+ int ec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), ec);
+ if (ec)
+ return (EFAULT);
+#else
if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
return (EFAULT);
+#endif
if (pfr_validate_table(&key.pfrkt_t, 0))
return (EINVAL);
p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
@@ -1166,6 +1400,9 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
{
struct pfr_ktable *p;
int n, nn;
+#if defined(__FreeBSD__)
+ int ec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ALLRSETS);
n = nn = pfr_table_count(filter, flags);
@@ -1180,8 +1417,14 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
continue;
if (n-- <= 0)
continue;
+#if defined(__FreeBSD__)
+ PF_COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), ec);
+ if (ec)
+ return (EFAULT);
+#else
if (copyout(&p->pfrkt_t, tbl++, sizeof(*tbl)))
return (EFAULT);
+#endif
}
if (n) {
printf("pfr_get_tables: corruption detected (%d).\n", n);
@@ -1198,7 +1441,15 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
struct pfr_ktable *p;
struct pfr_ktableworkq workq;
int s, n, nn;
+#if defined(__FreeBSD__)
+ int ec;
+ /*
+ * XXX Is it OK under LP64 environments?
+ */
+ long tzero = (long)time_second;
+#else
long tzero = time.tv_sec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS);
/* XXX PFR_FLAG_CLSTATS disabled */
@@ -1219,10 +1470,18 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
continue;
if (!(flags & PFR_FLAG_ATOMIC))
s = splsoftnet();
+#if defined(__FreeBSD__)
+ PF_COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), ec);
+ if (ec) {
+ splx(s);
+ return (EFAULT);
+ }
+#else
if (copyout(&p->pfrkt_ts, tbl++, sizeof(*tbl))) {
splx(s);
return (EFAULT);
}
+#endif
if (!(flags & PFR_FLAG_ATOMIC))
splx(s);
SLIST_INSERT_HEAD(&workq, p, pfrkt_workq);
@@ -1246,13 +1505,27 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
struct pfr_ktableworkq workq;
struct pfr_ktable *p, key;
int i, s, xzero = 0;
+#if defined(__FreeBSD__)
+ int ec;
+ /*
+ * XXX Is it OK under LP64 environments?
+ */
+ long tzero = (long)time_second;
+#else
long tzero = time.tv_sec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO);
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), ec);
+ if (ec)
+ return (EFAULT);
+#else
if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
return (EFAULT);
+#endif
if (pfr_validate_table(&key.pfrkt_t, 0))
return (EINVAL);
p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
@@ -1280,6 +1553,9 @@ pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
struct pfr_ktableworkq workq;
struct pfr_ktable *p, *q, key;
int i, s, xchange = 0, xdel = 0;
+#if defined(__FreeBSD__)
+ int ec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
if ((setflag & ~PFR_TFLAG_USRMASK) ||
@@ -1288,8 +1564,14 @@ pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
return (EINVAL);
SLIST_INIT(&workq);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), ec);
+ if (ec)
+ return (EFAULT);
+#else
if (copyin(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t)))
return (EFAULT);
+#endif
if (pfr_validate_table(&key.pfrkt_t, 0))
return (EINVAL);
p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key);
@@ -1370,6 +1652,9 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
struct pfr_addr ad;
struct pf_ruleset *rs;
int i, rv, xadd = 0, xaddr = 0;
+#if defined(__FreeBSD__)
+ int ec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_DUMMY|PFR_FLAG_ADDRSTOO);
if (size && !(flags & PFR_FLAG_ADDRSTOO))
@@ -1416,8 +1701,14 @@ _skip:
}
SLIST_INIT(&addrq);
for (i = 0; i < size; i++) {
+#if defined(__FreeBSD__)
+ PF_COPYIN(addr+i, &ad, sizeof(ad), ec);
+ if (ec)
+ senderr(EFAULT);
+#else
if (copyin(addr+i, &ad, sizeof(ad)))
senderr(EFAULT);
+#endif
if (pfr_validate_addr(&ad))
senderr(EINVAL);
if (pfr_lookup_addr(shadow, &ad, 1) != NULL)
@@ -1466,7 +1757,14 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
struct pfr_ktableworkq workq;
struct pf_ruleset *rs;
int s, xadd = 0, xchange = 0;
+#if defined(__FreeBSD__)
+ /*
+ * XXX Is it OK under LP64 environments?
+ */
+ long tzero = (long)time_second;
+#else
long tzero = time.tv_sec;
+#endif
ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY);
rs = pf_find_ruleset(trs->pfrt_anchor, trs->pfrt_ruleset);
@@ -1761,10 +2059,21 @@ pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr)
pfr_clean_node_mask(kt, &addrq);
pfr_destroy_kentries(&addrq);
}
+#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100)
+ if (kt->pfrkt_ip4 != NULL) {
+ RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip4);
+ free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
+ }
+ if (kt->pfrkt_ip6 != NULL) {
+ RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip6);
+ free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
+ }
+#else
if (kt->pfrkt_ip4 != NULL)
free((caddr_t)kt->pfrkt_ip4, M_RTABLE);
if (kt->pfrkt_ip6 != NULL)
free((caddr_t)kt->pfrkt_ip6, M_RTABLE);
+#endif
if (kt->pfrkt_shadow != NULL)
pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
if (kt->pfrkt_rs != NULL) {
@@ -1883,7 +2192,14 @@ pfr_attach_table(struct pf_ruleset *rs, char *name)
}
kt = pfr_lookup_table(&tbl);
if (kt == NULL) {
+#if defined(__FreeBSD__)
+ /*
+ * XXX Is it OK under LP64 environments?
+ */
+ kt = pfr_create_ktable(&tbl, (long)time_second, 1);
+#else
kt = pfr_create_ktable(&tbl, time.tv_sec, 1);
+#endif
if (kt == NULL)
return (NULL);
if (ac != NULL) {
@@ -1917,6 +2233,7 @@ pfr_detach_table(struct pfr_ktable *kt)
pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED);
}
+
int
pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter,
struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af)
@@ -2006,13 +2323,20 @@ pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af)
switch(af) {
case AF_INET:
+#if defined(__FreeBSD__)
+ kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#else
rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w);
+#endif
return w.pfrw_kentry;
case AF_INET6:
+#if defined(__FreeBSD__)
+ kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#else
rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w);
+#endif
return w.pfrw_kentry;
default:
return NULL;
}
}
-
diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h
index 058e425c300e..b90eb22d88e5 100644
--- a/sys/contrib/pf/net/pfvar.h
+++ b/sys/contrib/pf/net/pfvar.h
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: pfvar.h,v 1.170 2003/08/22 21:50:34 david Exp $ */
/*
@@ -38,7 +39,26 @@
#include <sys/tree.h>
#include <net/radix.h>
+#if defined(__FreeBSD__)
+#include <vm/uma.h>
+#else
#include <netinet/ip_ipsp.h>
+#endif
+
+#if defined(__FreeBSD__)
+#include <netinet/in.h>
+/*
+ * XXX
+ * If we include <netipsec/keydb.h>, we need _KERNEL definition.
+ * This makes pfctl compilation difficult.
+ */
+union sockaddr_union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+#endif
+
#include <netinet/tcp_fsm.h>
struct ip;
@@ -119,7 +139,11 @@ struct pf_addr_dyn {
struct ifnet *ifp;
struct pf_addr *addr;
sa_family_t af;
+#if defined(__FreeBSD__) && defined(HOOK_HACK)
+ eventhandler_tag hook_cookie;
+#else
void *hook_cookie;
+#endif
u_int8_t undefined;
};
@@ -129,6 +153,66 @@ struct pf_addr_dyn {
#ifdef _KERNEL
+#if defined(__FreeBSD__)
+#define splsoftnet() splnet()
+
+#define PF_NAME "pf"
+
+#define PR_NOWAIT M_NOWAIT
+#define pool_get(p, f) uma_zalloc(*(p), (f))
+#define pool_put(p, o) uma_zfree(*(p), (o))
+
+#define UMA_CREATE(var, type, desc) \
+ var = uma_zcreate(desc, sizeof(type), \
+ NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); \
+ if (var == NULL) break
+#define UMA_DESTROY(var) \
+ if(var) uma_zdestroy(var)
+
+extern struct mtx pf_task_mtx;
+#if defined(ALTQ)
+extern struct mtx pf_altq_mtx;
+extern int pfaltq_ref;
+#endif
+
+#define PF_ASSERT(h) mtx_assert(&pf_task_mtx, (h))
+
+#define PF_LOCK() do { \
+ PF_ASSERT(MA_NOTOWNED); \
+ mtx_lock(&pf_task_mtx); \
+} while(0)
+#define PF_UNLOCK() do { \
+ PF_ASSERT(MA_OWNED); \
+ mtx_unlock(&pf_task_mtx); \
+} while(0)
+
+#define PF_COPYIN(uaddr, kaddr, len, r) do { \
+ PF_UNLOCK(); \
+ r = copyin((uaddr), (kaddr), (len)); \
+ PF_LOCK(); \
+} while(0)
+
+#define PF_COPYOUT(kaddr, uaddr, len, r) do { \
+ PF_UNLOCK(); \
+ r = copyout((kaddr), (uaddr), (len)); \
+ PF_LOCK(); \
+} while(0)
+
+extern void init_pf_mutex(void);
+extern void destroy_pf_mutex(void);
+
+#define PF_MODVER 1
+#define PFLOG_MODVER 1
+#define PFSYNC_MODVER 1
+
+#define PFLOG_MINVER 1
+#define PFLOG_PREFVER PFLOG_MODVER
+#define PFLOG_MAXVER 1
+#define PFSYNC_MINVER 1
+#define PFSYNC_PREFVER PFSYNC_MODVER
+#define PFSYNC_MAXVER 1
+#endif
+
#ifdef INET
#ifndef INET6
#define PF_INET_ONLY
@@ -1101,6 +1185,13 @@ struct pfioc_table {
#define DIOCOSFPFLUSH _IO('D', 78)
#define DIOCOSFPADD _IOWR('D', 79, struct pf_osfp_ioctl)
#define DIOCOSFPGET _IOWR('D', 80, struct pf_osfp_ioctl)
+#if defined(__FreeBSD__)
+struct pf_ifspeed {
+ char ifname[IFNAMSIZ];
+ u_int32_t baudrate;
+};
+#define DIOCGIFSPEED _IOWR('D', 81, struct pf_ifspeed)
+#endif
#ifdef _KERNEL
RB_HEAD(pf_state_tree, pf_tree_node);
@@ -1135,9 +1226,17 @@ extern void pf_calc_skip_steps(struct pf_rulequeue *);
extern void pf_rule_set_qid(struct pf_rulequeue *);
extern u_int32_t pf_qname_to_qid(char *);
extern void pf_update_anchor_rules(void);
+#if defined(__FreeBSD__)
+extern uma_zone_t pf_tree_pl, pf_rule_pl, pf_addr_pl;
+extern uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
+extern uma_zone_t pfr_ktable_pl, pfr_kentry_pl;
+extern uma_zone_t pf_cache_pl, pf_cent_pl;
+extern uma_zone_t pf_state_scrub_pl;
+#else
extern struct pool pf_tree_pl, pf_rule_pl, pf_addr_pl;
extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
extern struct pool pf_state_scrub_pl;
+#endif
extern void pf_purge_timeout(void *);
extern void pf_purge_expired_states(void);
extern int pf_insert_state(struct pf_state *);
@@ -1234,7 +1333,12 @@ void pf_tag_unref(u_int16_t);
int pf_tag_packet(struct mbuf *, struct pf_tag *, int);
extern struct pf_status pf_status;
+
+#if defined(__FreeBSD__)
+extern uma_zone_t pf_frent_pl, pf_frag_pl;
+#else
extern struct pool pf_frent_pl, pf_frag_pl;
+#endif
struct pf_pool_limit {
void *pp;
@@ -1242,6 +1346,38 @@ struct pf_pool_limit {
};
extern struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
+#if defined(__FreeBSD__)
+struct pf_frent {
+ LIST_ENTRY(pf_frent) fr_next;
+ struct ip *fr_ip;
+ struct mbuf *fr_m;
+};
+
+struct pf_frcache {
+ LIST_ENTRY(pf_frcache) fr_next;
+ uint16_t fr_off;
+ uint16_t fr_end;
+};
+
+struct pf_fragment {
+ RB_ENTRY(pf_fragment) fr_entry;
+ TAILQ_ENTRY(pf_fragment) frag_next;
+ struct in_addr fr_src;
+ struct in_addr fr_dst;
+ u_int8_t fr_p; /* protocol of this fragment */
+ u_int8_t fr_flags; /* status flags */
+ u_int16_t fr_id; /* fragment id for reassemble */
+ u_int16_t fr_max; /* fragment data max */
+ u_int32_t fr_timeout;
+#define fr_queue fr_u.fru_queue
+#define fr_cache fr_u.fru_cache
+ union {
+ LIST_HEAD(pf_fragq, pf_frent) fru_queue; /* buffering */
+ LIST_HEAD(pf_cacheq, pf_frcache) fru_cache; /* non-buf */
+ } fr_u;
+};
+#endif /* (__FreeBSD__) */
+
#endif /* _KERNEL */
/* The fingerprint functions can be linked into userland programs (tcpdump) */
@@ -1255,7 +1391,12 @@ struct pf_osfp_enlist *
pf_osfp_fingerprint_hdr(const struct ip *, const struct tcphdr *);
void pf_osfp_flush(void);
int pf_osfp_get(struct pf_osfp_ioctl *);
+#if defined(__FreeBSD__)
+int pf_osfp_initialize(void);
+void pf_osfp_cleanup(void);
+#else
void pf_osfp_initialize(void);
+#endif
int pf_osfp_match(struct pf_osfp_enlist *, pf_osfp_t);
struct pf_os_fingerprint *
pf_osfp_validate(void);
diff --git a/sys/contrib/pf/netinet/in4_cksum.c b/sys/contrib/pf/netinet/in4_cksum.c
index 1c40f2e05b6e..ca2256f2e96f 100644
--- a/sys/contrib/pf/netinet/in4_cksum.c
+++ b/sys/contrib/pf/netinet/in4_cksum.c
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* $OpenBSD: in4_cksum.c,v 1.7 2003/06/02 23:28:13 millert Exp $ */
/* $KAME: in4_cksum.c,v 1.10 2001/11/30 10:06:15 itojun Exp $ */
/* $NetBSD: in_cksum.c,v 1.13 1996/10/13 02:03:03 christos Exp $ */
@@ -72,6 +73,39 @@
#include <netinet/ip.h>
#include <netinet/ip_var.h>
+#if defined(__FreeBSD__) && defined(__i386__)
+/*
+ * Copied from FreeBSD 5.0 sys/i386/i386/in_cksum.c
+ * XXX
+ * Currently support I386 processor only.
+ * In the long run, we need an optimized cksum routines for each Tier1
+ * architecture. Due to the lack of available hardware except I386 I
+ * can't support other processors now. For those users which use Sparc64,
+ * Alpha processors can use more optimized version in FreeBSD.
+ * See sys/$ARCH/$ARCH/in_cksum.c where $ARCH=`uname -p`
+ */
+
+/*
+ * These asm statements require __volatile because they pass information
+ * via the condition codes. GCC does not currently provide a way to specify
+ * the condition codes as an input or output operand.
+ *
+ * The LOAD macro below is effectively a prefetch into cache. GCC will
+ * load the value into a register but will not use it. Since modern CPUs
+ * reorder operations, this will generally take place in parallel with
+ * other calculations.
+ */
+#define ADD(n) __asm __volatile \
+ ("addl %1, %0" : "+r" (sum) : \
+ "g" (((const u_int32_t *)w)[n / 4]))
+#define ADDC(n) __asm __volatile \
+ ("adcl %1, %0" : "+r" (sum) : \
+ "g" (((const u_int32_t *)w)[n / 4]))
+#define LOAD(n) __asm __volatile \
+ ("" : : "r" (((const u_int32_t *)w)[n / 4]))
+#define MOP __asm __volatile \
+ ("adcl $0, %0" : "+r" (sum))
+#endif
/*
* Checksum routine for Internet Protocol family headers (Portable Version).
* This is only for IPv4 pseudo header checksum.
@@ -86,6 +120,11 @@
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
+#if defined(__FreeBSD__)
+int
+in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
+#endif
+
int
in4_cksum(m, nxt, off, len)
struct mbuf *m;
@@ -158,6 +197,134 @@ in4_cksum(m, nxt, off, len)
if (len < mlen)
mlen = len;
len -= mlen;
+#if defined(__FreeBSD__) && defined(__i386__)
+ /*
+ * Force to long boundary so we do longword aligned
+ * memory operations
+ */
+ if (3 & (int) w) {
+ REDUCE;
+ if ((1 & (int) w) && (mlen > 0)) {
+ sum <<= 8;
+ s_util.c[0] = *(char *)w;
+ w = (u_short *)((char *)w + 1);
+ mlen--;
+ byte_swapped = 1;
+ }
+ if ((2 & (int) w) && (mlen >= 2)) {
+ sum += *w++;
+ mlen -= 2;
+ }
+ }
+ /*
+ * Advance to a 486 cache line boundary.
+ */
+ if (4 & (int) w && mlen >= 4) {
+ ADD(0);
+ MOP;
+ w += 2;
+ mlen -= 4;
+ }
+ if (8 & (int) w && mlen >= 8) {
+ ADD(0);
+ ADDC(4);
+ MOP;
+ w += 4;
+ mlen -= 8;
+ }
+ /*
+ * Do as much of the checksum as possible 32 bits at at time.
+ * In fact, this loop is unrolled to make overhead from
+ * branches &c small.
+ */
+ mlen -= 1;
+ while ((mlen -= 32) >= 0) {
+ /*
+ * Add with carry 16 words and fold in the last
+ * carry by adding a 0 with carry.
+ *
+ * The early ADD(16) and the LOAD(32) are to load
+ * the next 2 cache lines in advance on 486's. The
+ * 486 has a penalty of 2 clock cycles for loading
+ * a cache line, plus whatever time the external
+ * memory takes to load the first word(s) addressed.
+ * These penalties are unavoidable. Subsequent
+ * accesses to a cache line being loaded (and to
+ * other external memory?) are delayed until the
+ * whole load finishes. These penalties are mostly
+ * avoided by not accessing external memory for
+ * 8 cycles after the ADD(16) and 12 cycles after
+ * the LOAD(32). The loop terminates when mlen
+ * is initially 33 (not 32) to guaranteed that
+ * the LOAD(32) is within bounds.
+ */
+ ADD(16);
+ ADDC(0);
+ ADDC(4);
+ ADDC(8);
+ ADDC(12);
+ LOAD(32);
+ ADDC(20);
+ ADDC(24);
+ ADDC(28);
+ MOP;
+ w += 16;
+ }
+ mlen += 32 + 1;
+ if (mlen >= 32) {
+ ADD(16);
+ ADDC(0);
+ ADDC(4);
+ ADDC(8);
+ ADDC(12);
+ ADDC(20);
+ ADDC(24);
+ ADDC(28);
+ MOP;
+ w += 16;
+ mlen -= 32;
+ }
+ if (mlen >= 16) {
+ ADD(0);
+ ADDC(4);
+ ADDC(8);
+ ADDC(12);
+ MOP;
+ w += 8;
+ mlen -= 16;
+ }
+ if (mlen >= 8) {
+ ADD(0);
+ ADDC(4);
+ MOP;
+ w += 4;
+ mlen -= 8;
+ }
+ if (mlen == 0 && byte_swapped == 0)
+ continue; /* worth 1% maybe ?? */
+ REDUCE;
+ while ((mlen -= 2) >= 0) {
+ sum += *w++;
+ }
+ if (byte_swapped) {
+ REDUCE;
+ sum <<= 8;
+ byte_swapped = 0;
+ if (mlen == -1) {
+ s_util.c[1] = *(char *)w;
+ sum += s_util.s;
+ mlen = 0;
+ } else
+ mlen = -1;
+ } else if (mlen == -1)
+ /*
+ * This mbuf has odd number of bytes.
+ * There could be a word split betwen
+ * this mbuf and the next mbuf.
+ * Save the last byte (to prepend to next mbuf).
+ */
+ s_util.c[0] = *(char *)w;
+#else
/*
* Force to even boundary.
*/
@@ -204,6 +371,7 @@ in4_cksum(m, nxt, off, len)
mlen = -1;
} else if (mlen == -1)
s_util.c[0] = *(u_int8_t *)w;
+#endif
}
if (len)
printf("cksum4: out of data\n");