Deleted Added
full compact
0a1
> /* $FreeBSD: head/sys/contrib/pf/net/pf_ioctl.c 126261 2004-02-26 02:34:12Z mlaier $ */
36a38,42
> #if defined(__FreeBSD__)
> #include "opt_inet.h"
> #include "opt_inet6.h"
> #endif
>
45a52,55
> #include <sys/malloc.h>
> #if defined(__FreeBSD__)
> #include <sys/conf.h>
> #else
48c58
< #include <sys/malloc.h>
---
> #endif
65a76,78
> #if defined(__FreeBSD__) && (__FreeBSD_version < 501108)
> #include <netinet6/ip6protosw.h>
> #endif
71a85,103
> #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
74a107
> #endif
80a114,116
> #if defined(__FreeBSD__)
> int pfioctl(dev_t, u_long, caddr_t, int, struct thread *);
> #else
81a118
> #endif
82a120,125
> #if defined(__FreeBSD__)
> extern struct callout pf_expire_to;
> #if __FreeBSD_version < 501108
> extern struct protosw inetsw[];
> #endif
> #else
83a127
> #endif
91a136,228
>
> #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;
>
92a230,374
> 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
132c414
< timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
---
> timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
153a436
> #endif /* __FreeBSD__ */
154a438
> #if !defined(__FreeBSD__)
161a446
> #endif
162a448
> #if !defined(__FreeBSD__)
169a456
> #endif
352c639,640
< if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 || ruleset->topen)
---
> if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 ||
> ruleset->topen)
500a789
> #if defined(__FreeBSD__)
501a791,793
> pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
> #else
> int
502a795
> #endif
544a838,840
> #if defined(__FreeBSD__)
> case DIOCGIFSPEED:
> #endif
573a870,872
> #if defined(__FreeBSD__)
> case DIOCGIFSPEED:
> #endif
578a878,881
> #if defined(__FreeBSD__)
> PF_LOCK();
> #endif
>
585a889,898
> #if defined(__FreeBSD__)
> PF_UNLOCK();
> error = hook_pf();
> PF_LOCK();
> if (error) {
> DPFPRINTF(PF_DEBUG_MISC,
> ("pf: pfil registeration fail\n"));
> break;
> }
> #endif
588a902,904
> #if defined(__FreeBSD__)
> pf_status.since = time_second;
> #else
589a906
> #endif
590a908,911
> #if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
> snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
> status_ifp->if_name, status_ifp->if_unit);
> #else
592a914
> #endif
601a924,933
> #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
1110a1443,1445
> #if defined(__FreeBSD__)
> state->creation = time_second;
> #else
1111a1447
> #endif
1146a1483,1486
> #if defined(__FreeBSD__)
> if (ps->state.expire > time_second)
> ps->state.expire -= time_second;
> #else
1148a1489
> #endif
1166a1508,1510
> #if defined(__FreeBSD__)
> PF_UNLOCK();
> #endif
1172a1517,1519
> #if defined(__FreeBSD__)
> int secs = time_second;
> #else
1173a1521
> #endif
1189a1538,1540
> #if defined(__FreeBSD__)
> PF_COPYOUT(&pstore, p, sizeof(*p), error);
> #else
1190a1542
> #endif
1238a1591,1594
> #if defined(__FreeBSD__) && (__FreeBSD_version < 501113)
> snprintf(pf_status.ifname, IFNAMSIZ, "%s%d",
> status_ifp->if_name, status_ifp->if_unit);
> #else
1240a1597
> #endif
1341a1699,1701
> #if defined(__FreeBSD__)
> uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit);
> #else
1346a1707
> #endif
1372a1734,1753
> #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__ */
>
1398a1780,1786
> #if defined(__FreeBSD__)
> if (error == 0) {
> mtx_lock(&pf_altq_mtx);
> pfaltq_running = 1;
> mtx_unlock(&pf_altq_mtx);
> }
> #else
1400a1789
> #endif
1431a1821,1827
> #if defined(__FreeBSD__)
> if (error == 0) {
> mtx_lock(&pf_altq_mtx);
> pfaltq_running = 0;
> mtx_unlock(&pf_altq_mtx);
> }
> #else
1433a1830
> #endif
1447a1845,1847
> #if defined(__FreeBSD__)
> PF_UNLOCK();
> #endif
1448a1849,1851
> #if defined(__FreeBSD__)
> PF_LOCK();
> #endif
1484a1888,1890
> #if defined(__FreeBSD__)
> PF_UNLOCK();
> #endif
1485a1892,1894
> #if defined(__FreeBSD__)
> PF_LOCK();
> #endif
1519a1929,1931
> #if defined(__FreeBSD__)
> PF_UNLOCK();
> #endif
1520a1933,1935
> #if defined(__FreeBSD__)
> PF_LOCK();
> #endif
1532a1948,1950
> #if defined(__FreeBSD__)
> PF_UNLOCK();
> #endif
1538a1957,1959
> #if defined(__FreeBSD__)
> PF_LOCK();
> #endif
1623a2045,2047
> #if defined(__FreeBSD__)
> PF_UNLOCK();
> #endif
1624a2049,2051
> #if defined(__FreeBSD__)
> PF_LOCK();
> #endif
2155a2583,2587
> #if defined(__FreeBSD__)
> PF_UNLOCK();
> #endif
> return (error);
> }
2156a2589,2618
> #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);
>
2158a2621,3292
>
> 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__ */