diff options
author | Max Laier <mlaier@FreeBSD.org> | 2004-02-26 02:34:12 +0000 |
---|---|---|
committer | Max Laier <mlaier@FreeBSD.org> | 2004-02-26 02:34:12 +0000 |
commit | 2bbe8ffc9d0ed0a0795c6e4af4b11f4c7be49421 (patch) | |
tree | 93a5df3113f8f9cf3fd0b519d7ad89db6831f1fc /sys/contrib | |
parent | 3ef891af51c7b93236727ba7aa6e2490f1cc8158 (diff) | |
download | src-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.c | 165 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pflog.h | 4 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pfsync.c | 199 | ||||
-rw-r--r-- | sys/contrib/pf/net/if_pfsync.h | 8 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf.c | 870 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_ioctl.c | 1140 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_norm.c | 187 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_osfp.c | 45 | ||||
-rw-r--r-- | sys/contrib/pf/net/pf_table.c | 328 | ||||
-rw-r--r-- | sys/contrib/pf/net/pfvar.h | 141 | ||||
-rw-r--r-- | sys/contrib/pf/netinet/in4_cksum.c | 168 |
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"); |