1/*
2 * Copyright (c) 2007-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*	$apfw: git commit b6bf13f8321283cd7ee82b1795e86506084b1b95 $ */
30/*	$OpenBSD: pf_ioctl.c,v 1.175 2007/02/26 22:47:43 deraadt Exp $ */
31
32/*
33 * Copyright (c) 2001 Daniel Hartmeier
34 * Copyright (c) 2002,2003 Henning Brauer
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 *
41 *    - Redistributions of source code must retain the above copyright
42 *      notice, this list of conditions and the following disclaimer.
43 *    - Redistributions in binary form must reproduce the above
44 *      copyright notice, this list of conditions and the following
45 *      disclaimer in the documentation and/or other materials provided
46 *      with the distribution.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
51 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
52 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
53 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
54 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
55 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
56 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
58 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
59 * POSSIBILITY OF SUCH DAMAGE.
60 *
61 * Effort sponsored in part by the Defense Advanced Research Projects
62 * Agency (DARPA) and Air Force Research Laboratory, Air Force
63 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
64 *
65 */
66
67#include <machine/endian.h>
68#include <sys/param.h>
69#include <sys/systm.h>
70#include <sys/mbuf.h>
71#include <sys/filio.h>
72#include <sys/fcntl.h>
73#include <sys/socket.h>
74#include <sys/socketvar.h>
75#include <sys/kernel.h>
76#include <sys/time.h>
77#include <sys/proc_internal.h>
78#include <sys/malloc.h>
79#include <sys/kauth.h>
80#include <sys/conf.h>
81#include <sys/mcache.h>
82#include <sys/queue.h>
83
84#include <mach/vm_param.h>
85
86#include <net/dlil.h>
87#include <net/if.h>
88#include <net/if_types.h>
89#include <net/route.h>
90
91#include <netinet/in.h>
92#include <netinet/in_var.h>
93#include <netinet/in_systm.h>
94#include <netinet/ip.h>
95#include <netinet/ip_var.h>
96#include <netinet/ip_icmp.h>
97#include <netinet/if_ether.h>
98
99#if DUMMYNET
100#include <netinet/ip_dummynet.h>
101#else
102struct ip_fw_args;
103#endif /* DUMMYNET */
104
105#include <libkern/crypto/md5.h>
106
107#include <machine/machine_routines.h>
108
109#include <miscfs/devfs/devfs.h>
110
111#include <net/pfvar.h>
112
113#if NPFSYNC
114#include <net/if_pfsync.h>
115#endif /* NPFSYNC */
116
117#if PFLOG
118#include <net/if_pflog.h>
119#endif /* PFLOG */
120
121#if INET6
122#include <netinet/ip6.h>
123#include <netinet/in_pcb.h>
124#endif /* INET6 */
125
126#if PF_ALTQ
127#include <net/altq/altq.h>
128#include <net/altq/altq_cbq.h>
129#include <net/classq/classq_red.h>
130#include <net/classq/classq_rio.h>
131#include <net/classq/classq_blue.h>
132#include <net/classq/classq_sfb.h>
133#endif /* PF_ALTQ */
134
135#include <dev/random/randomdev.h>
136
137#if 0
138static void pfdetach(void);
139#endif
140static int pfopen(dev_t, int, int, struct proc *);
141static int pfclose(dev_t, int, int, struct proc *);
142static int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
143static int pfioctl_ioc_table(u_long, struct pfioc_table_32 *,
144    struct pfioc_table_64 *, struct proc *);
145static int pfioctl_ioc_tokens(u_long, struct pfioc_tokens_32 *,
146    struct pfioc_tokens_64 *, struct proc *);
147static int pfioctl_ioc_rule(u_long, int, struct pfioc_rule *, struct proc *);
148static int pfioctl_ioc_state_kill(u_long, struct pfioc_state_kill *,
149    struct proc *);
150static int pfioctl_ioc_state(u_long, struct pfioc_state *, struct proc *);
151static int pfioctl_ioc_states(u_long, struct pfioc_states_32 *,
152    struct pfioc_states_64 *, struct proc *);
153static int pfioctl_ioc_natlook(u_long, struct pfioc_natlook *, struct proc *);
154static int pfioctl_ioc_tm(u_long, struct pfioc_tm *, struct proc *);
155static int pfioctl_ioc_limit(u_long, struct pfioc_limit *, struct proc *);
156static int pfioctl_ioc_pooladdr(u_long, struct pfioc_pooladdr *, struct proc *);
157static int pfioctl_ioc_ruleset(u_long, struct pfioc_ruleset *, struct proc *);
158static int pfioctl_ioc_trans(u_long, struct pfioc_trans_32 *,
159    struct pfioc_trans_64 *, struct proc *);
160static int pfioctl_ioc_src_nodes(u_long, struct pfioc_src_nodes_32 *,
161    struct pfioc_src_nodes_64 *, struct proc *);
162static int pfioctl_ioc_src_node_kill(u_long, struct pfioc_src_node_kill *,
163    struct proc *);
164static int pfioctl_ioc_iface(u_long, struct pfioc_iface_32 *,
165    struct pfioc_iface_64 *, struct proc *);
166static struct pf_pool *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
167    u_int8_t, u_int8_t, u_int8_t);
168static void pf_mv_pool(struct pf_palist *, struct pf_palist *);
169static void pf_empty_pool(struct pf_palist *);
170#if PF_ALTQ
171static int pf_begin_altq(u_int32_t *);
172static int pf_rollback_altq(u_int32_t);
173static int pf_commit_altq(u_int32_t);
174static int pf_enable_altq(struct pf_altq *);
175static int pf_disable_altq(struct pf_altq *);
176static void pf_altq_copyin(struct pf_altq *, struct pf_altq *);
177static void pf_altq_copyout(struct pf_altq *, struct pf_altq *);
178#endif /* PF_ALTQ */
179static int pf_begin_rules(u_int32_t *, int, const char *);
180static int pf_rollback_rules(u_int32_t, int, char *);
181static int pf_setup_pfsync_matching(struct pf_ruleset *);
182static void pf_hash_rule(MD5_CTX *, struct pf_rule *);
183static void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *, u_int8_t);
184static int pf_commit_rules(u_int32_t, int, char *);
185static void pf_rule_copyin(struct pf_rule *, struct pf_rule *, struct proc *,
186    int);
187static void pf_rule_copyout(struct pf_rule *, struct pf_rule *);
188static void pf_state_export(struct pfsync_state *, struct pf_state_key *,
189    struct pf_state *);
190static void pf_state_import(struct pfsync_state *, struct pf_state_key *,
191    struct pf_state *);
192static void pf_pooladdr_copyin(struct pf_pooladdr *, struct pf_pooladdr *);
193static void pf_pooladdr_copyout(struct pf_pooladdr *, struct pf_pooladdr *);
194static void pf_expire_states_and_src_nodes(struct pf_rule *);
195static void pf_delete_rule_from_ruleset(struct pf_ruleset *,
196    int, struct pf_rule *);
197static void pf_addrwrap_setup(struct pf_addr_wrap *);
198static int pf_rule_setup(struct pfioc_rule *, struct pf_rule *,
199    struct pf_ruleset *);
200static void pf_delete_rule_by_owner(char *, u_int32_t);
201static int pf_delete_rule_by_ticket(struct pfioc_rule *, u_int32_t);
202static void pf_ruleset_cleanup(struct pf_ruleset *, int);
203static void pf_deleterule_anchor_step_out(struct pf_ruleset **,
204    int, struct pf_rule **);
205
206#define	PF_CDEV_MAJOR	(-1)
207
208static struct cdevsw pf_cdevsw = {
209	/* open */	pfopen,
210	/* close */	pfclose,
211	/* read */	eno_rdwrt,
212	/* write */	eno_rdwrt,
213	/* ioctl */	pfioctl,
214	/* stop */	eno_stop,
215	/* reset */	eno_reset,
216	/* tty */	NULL,
217	/* select */	eno_select,
218	/* mmap */	eno_mmap,
219	/* strategy */	eno_strat,
220	/* getc */	eno_getc,
221	/* putc */	eno_putc,
222	/* type */	0
223};
224
225static void pf_attach_hooks(void);
226#if 0
227/* currently unused along with pfdetach() */
228static void pf_detach_hooks(void);
229#endif
230
231/*
232 * This is set during DIOCSTART/DIOCSTOP with pf_perim_lock held as writer,
233 * and used in pf_af_hook() for performance optimization, such that packets
234 * will enter pf_test() or pf_test6() only when PF is running.
235 */
236int pf_is_enabled = 0;
237
238#if PF_ALTQ
239u_int32_t altq_allowed = 0;
240#endif /* PF_ALTQ */
241
242u_int32_t pf_hash_seed;
243
244/*
245 * These are the pf enabled reference counting variables
246 */
247static u_int64_t pf_enabled_ref_count;
248static u_int32_t nr_tokens = 0;
249static u_int64_t pffwrules;
250static u_int32_t pfdevcnt;
251
252SLIST_HEAD(list_head, pfioc_kernel_token);
253static struct list_head token_list_head;
254
255struct pf_rule		 pf_default_rule;
256#if PF_ALTQ
257static int		 pf_altq_running;
258#endif /* PF_ALTQ */
259
260#define	TAGID_MAX	 50000
261#if !PF_ALTQ
262static TAILQ_HEAD(pf_tags, pf_tagname)	pf_tags =
263    TAILQ_HEAD_INITIALIZER(pf_tags);
264#else /* PF_ALTQ */
265static TAILQ_HEAD(pf_tags, pf_tagname)
266    pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
267    pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids);
268#endif /* PF_ALTQ */
269
270#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
271#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
272#endif
273static u_int16_t	 tagname2tag(struct pf_tags *, char *);
274static void		 tag2tagname(struct pf_tags *, u_int16_t, char *);
275static void		 tag_unref(struct pf_tags *, u_int16_t);
276static int		 pf_rtlabel_add(struct pf_addr_wrap *);
277static void		 pf_rtlabel_remove(struct pf_addr_wrap *);
278static void		 pf_rtlabel_copyout(struct pf_addr_wrap *);
279
280#if INET
281static int pf_inet_hook(struct ifnet *, struct mbuf **, int,
282    struct ip_fw_args *);
283#endif /* INET */
284#if INET6
285static int pf_inet6_hook(struct ifnet *, struct mbuf **, int,
286    struct ip_fw_args *);
287#endif /* INET6 */
288
289#define	DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
290
291/*
292 * Helper macros for ioctl structures which vary in size (32-bit vs. 64-bit)
293 */
294#define	PFIOCX_STRUCT_DECL(s)						\
295struct {								\
296	union {								\
297		struct s##_32	_s##_32;				\
298		struct s##_64	_s##_64;				\
299	} _u;								\
300} *s##_un = NULL							\
301
302#define	PFIOCX_STRUCT_BEGIN(a, s, _action) {				\
303	VERIFY(s##_un == NULL);						\
304	s##_un = _MALLOC(sizeof (*s##_un), M_TEMP, M_WAITOK|M_ZERO);	\
305	if (s##_un == NULL) {						\
306		_action							\
307	} else {							\
308		if (p64)						\
309			bcopy(a, &s##_un->_u._s##_64,			\
310			    sizeof (struct s##_64));			\
311		else							\
312			bcopy(a, &s##_un->_u._s##_32,			\
313			    sizeof (struct s##_32));			\
314	}								\
315}
316
317#define	PFIOCX_STRUCT_END(s, a) {					\
318	VERIFY(s##_un != NULL);						\
319	if (p64)							\
320		bcopy(&s##_un->_u._s##_64, a, sizeof (struct s##_64));	\
321	else								\
322		bcopy(&s##_un->_u._s##_32, a, sizeof (struct s##_32));	\
323	_FREE(s##_un, M_TEMP);						\
324	s##_un = NULL;							\
325}
326
327#define	PFIOCX_STRUCT_ADDR32(s)		(&s##_un->_u._s##_32)
328#define	PFIOCX_STRUCT_ADDR64(s)		(&s##_un->_u._s##_64)
329
330/*
331 * Helper macros for regular ioctl structures.
332 */
333#define	PFIOC_STRUCT_BEGIN(a, v, _action) {				\
334	VERIFY((v) == NULL);						\
335	(v) = _MALLOC(sizeof (*(v)), M_TEMP, M_WAITOK|M_ZERO);		\
336	if ((v) == NULL) {						\
337		_action							\
338	} else {							\
339		bcopy(a, v, sizeof (*(v)));				\
340	}								\
341}
342
343#define	PFIOC_STRUCT_END(v, a) {					\
344	VERIFY((v) != NULL);						\
345	bcopy(v, a, sizeof (*(v)));					\
346	_FREE(v, M_TEMP);						\
347	(v) = NULL;							\
348}
349
350#define	PFIOC_STRUCT_ADDR32(s)		(&s##_un->_u._s##_32)
351#define	PFIOC_STRUCT_ADDR64(s)		(&s##_un->_u._s##_64)
352
353static lck_attr_t *pf_perim_lock_attr;
354static lck_grp_t *pf_perim_lock_grp;
355static lck_grp_attr_t *pf_perim_lock_grp_attr;
356
357static lck_attr_t *pf_lock_attr;
358static lck_grp_t *pf_lock_grp;
359static lck_grp_attr_t *pf_lock_grp_attr;
360
361struct thread *pf_purge_thread;
362
363extern void pfi_kifaddr_update(void *);
364
365/* pf enable ref-counting helper functions */
366static u_int64_t		generate_token(struct proc *);
367static int			remove_token(struct pfioc_remove_token *);
368static void			invalidate_all_tokens(void);
369
370static u_int64_t
371generate_token(struct proc *p)
372{
373	u_int64_t token_value;
374	struct pfioc_kernel_token *new_token;
375
376	new_token = _MALLOC(sizeof (struct pfioc_kernel_token), M_TEMP,
377	    M_WAITOK|M_ZERO);
378
379	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
380
381	if (new_token == NULL) {
382		/* malloc failed! bail! */
383		printf("%s: unable to allocate pf token structure!", __func__);
384		return (0);
385	}
386
387	token_value = VM_KERNEL_ADDRPERM((u_int64_t)(uintptr_t)new_token);
388
389	new_token->token.token_value = token_value;
390	new_token->token.pid = proc_pid(p);
391	proc_name(new_token->token.pid, new_token->token.proc_name,
392	    sizeof (new_token->token.proc_name));
393	new_token->token.timestamp = pf_calendar_time_second();
394
395	SLIST_INSERT_HEAD(&token_list_head, new_token, next);
396	nr_tokens++;
397
398	return (token_value);
399}
400
401static int
402remove_token(struct pfioc_remove_token *tok)
403{
404	struct pfioc_kernel_token *entry, *tmp;
405
406	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
407
408	SLIST_FOREACH_SAFE(entry, &token_list_head, next, tmp) {
409		if (tok->token_value == entry->token.token_value) {
410			SLIST_REMOVE(&token_list_head, entry,
411			    pfioc_kernel_token, next);
412			_FREE(entry, M_TEMP);
413			nr_tokens--;
414			return (0);    /* success */
415		}
416	}
417
418	printf("pf : remove failure\n");
419	return (ESRCH);    /* failure */
420}
421
422static void
423invalidate_all_tokens(void)
424{
425	struct pfioc_kernel_token *entry, *tmp;
426
427	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
428
429	SLIST_FOREACH_SAFE(entry, &token_list_head, next, tmp) {
430		SLIST_REMOVE(&token_list_head, entry, pfioc_kernel_token, next);
431		_FREE(entry, M_TEMP);
432	}
433
434	nr_tokens = 0;
435}
436
437void
438pfinit(void)
439{
440	u_int32_t *t = pf_default_rule.timeout;
441	int maj;
442
443	pf_perim_lock_grp_attr = lck_grp_attr_alloc_init();
444	pf_perim_lock_grp = lck_grp_alloc_init("pf_perim",
445	    pf_perim_lock_grp_attr);
446	pf_perim_lock_attr = lck_attr_alloc_init();
447	lck_rw_init(pf_perim_lock, pf_perim_lock_grp, pf_perim_lock_attr);
448
449	pf_lock_grp_attr = lck_grp_attr_alloc_init();
450	pf_lock_grp = lck_grp_alloc_init("pf", pf_lock_grp_attr);
451	pf_lock_attr = lck_attr_alloc_init();
452	lck_mtx_init(pf_lock, pf_lock_grp, pf_lock_attr);
453
454	pool_init(&pf_rule_pl, sizeof (struct pf_rule), 0, 0, 0, "pfrulepl",
455	    NULL);
456	pool_init(&pf_src_tree_pl, sizeof (struct pf_src_node), 0, 0, 0,
457	    "pfsrctrpl", NULL);
458	pool_init(&pf_state_pl, sizeof (struct pf_state), 0, 0, 0, "pfstatepl",
459	    NULL);
460	pool_init(&pf_state_key_pl, sizeof (struct pf_state_key), 0, 0, 0,
461	    "pfstatekeypl", NULL);
462	pool_init(&pf_app_state_pl, sizeof (struct pf_app_state), 0, 0, 0,
463	    "pfappstatepl", NULL);
464#if PF_ALTQ
465	pool_init(&pf_altq_pl, sizeof (struct pf_altq), 0, 0, 0, "pfaltqpl",
466	    NULL);
467#endif /* PF_ALTQ */
468	pool_init(&pf_pooladdr_pl, sizeof (struct pf_pooladdr), 0, 0, 0,
469	    "pfpooladdrpl", NULL);
470	pfr_initialize();
471	pfi_initialize();
472	pf_osfp_initialize();
473
474	pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp,
475	    pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0);
476
477	if (max_mem <= 256*1024*1024)
478		pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
479		    PFR_KENTRY_HIWAT_SMALL;
480
481	RB_INIT(&tree_src_tracking);
482	RB_INIT(&pf_anchors);
483	pf_init_ruleset(&pf_main_ruleset);
484	TAILQ_INIT(&pf_pabuf);
485	TAILQ_INIT(&state_list);
486#if PF_ALTQ
487	TAILQ_INIT(&pf_altqs[0]);
488	TAILQ_INIT(&pf_altqs[1]);
489	pf_altqs_active = &pf_altqs[0];
490	pf_altqs_inactive = &pf_altqs[1];
491
492	PE_parse_boot_argn("altq", &altq_allowed, sizeof (altq_allowed));
493
494	_CASSERT(ALTRQ_PURGE == CLASSQRQ_PURGE);
495	_CASSERT(ALTRQ_PURGE_SC == CLASSQRQ_PURGE_SC);
496	_CASSERT(ALTRQ_EVENT == CLASSQRQ_EVENT);
497
498	_CASSERT(ALTDQ_REMOVE == CLASSQDQ_REMOVE);
499	_CASSERT(ALTDQ_POLL == CLASSQDQ_POLL);
500#endif /* PF_ALTQ */
501
502	_CASSERT((SC_BE & SCIDX_MASK) == SCIDX_BE);
503	_CASSERT((SC_BK_SYS & SCIDX_MASK) == SCIDX_BK_SYS);
504	_CASSERT((SC_BK & SCIDX_MASK) == SCIDX_BK);
505	_CASSERT((SC_RD & SCIDX_MASK) == SCIDX_RD);
506	_CASSERT((SC_OAM & SCIDX_MASK) == SCIDX_OAM);
507	_CASSERT((SC_AV & SCIDX_MASK) == SCIDX_AV);
508	_CASSERT((SC_RV & SCIDX_MASK) == SCIDX_RV);
509	_CASSERT((SC_VI & SCIDX_MASK) == SCIDX_VI);
510	_CASSERT((SC_VO & SCIDX_MASK) == SCIDX_VO);
511	_CASSERT((SC_CTL & SCIDX_MASK) == SCIDX_CTL);
512
513	/* default rule should never be garbage collected */
514	pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
515	pf_default_rule.action = PF_PASS;
516	pf_default_rule.nr = -1;
517	pf_default_rule.rtableid = IFSCOPE_NONE;
518
519	/* initialize default timeouts */
520	t[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
521	t[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
522	t[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
523	t[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
524	t[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
525	t[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
526	t[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
527	t[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
528	t[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
529	t[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
530	t[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
531	t[PFTM_GREv1_FIRST_PACKET] = PFTM_GREv1_FIRST_PACKET_VAL;
532	t[PFTM_GREv1_INITIATING] = PFTM_GREv1_INITIATING_VAL;
533	t[PFTM_GREv1_ESTABLISHED] = PFTM_GREv1_ESTABLISHED_VAL;
534	t[PFTM_ESP_FIRST_PACKET] = PFTM_ESP_FIRST_PACKET_VAL;
535	t[PFTM_ESP_INITIATING] = PFTM_ESP_INITIATING_VAL;
536	t[PFTM_ESP_ESTABLISHED] = PFTM_ESP_ESTABLISHED_VAL;
537	t[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
538	t[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
539	t[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
540	t[PFTM_FRAG] = PFTM_FRAG_VAL;
541	t[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
542	t[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
543	t[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
544	t[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
545	t[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
546
547	pf_normalize_init();
548	bzero(&pf_status, sizeof (pf_status));
549	pf_status.debug = PF_DEBUG_URGENT;
550	pf_hash_seed = RandomULong();
551
552	/* XXX do our best to avoid a conflict */
553	pf_status.hostid = random();
554
555	if (kernel_thread_start(pf_purge_thread_fn, NULL,
556	    &pf_purge_thread) != 0) {
557		printf("%s: unable to start purge thread!", __func__);
558		return;
559	}
560
561	maj = cdevsw_add(PF_CDEV_MAJOR, &pf_cdevsw);
562	if (maj == -1) {
563		printf("%s: failed to allocate major number!\n", __func__);
564		return;
565	}
566	(void) devfs_make_node(makedev(maj, PFDEV_PF), DEVFS_CHAR,
567	    UID_ROOT, GID_WHEEL, 0600, "pf", 0);
568
569	(void) devfs_make_node(makedev(maj, PFDEV_PFM), DEVFS_CHAR,
570	    UID_ROOT, GID_WHEEL, 0600, "pfm", 0);
571
572	pf_attach_hooks();
573}
574
575#if 0
576static void
577pfdetach(void)
578{
579	struct pf_anchor	*anchor;
580	struct pf_state		*state;
581	struct pf_src_node	*node;
582	struct pfioc_table	pt;
583	u_int32_t		ticket;
584	int			i;
585	char			r = '\0';
586
587	pf_detach_hooks();
588
589	pf_status.running = 0;
590	wakeup(pf_purge_thread_fn);
591
592	/* clear the rulesets */
593	for (i = 0; i < PF_RULESET_MAX; i++)
594		if (pf_begin_rules(&ticket, i, &r) == 0)
595				pf_commit_rules(ticket, i, &r);
596#if PF_ALTQ
597	if (pf_begin_altq(&ticket) == 0)
598		pf_commit_altq(ticket);
599#endif /* PF_ALTQ */
600
601	/* clear states */
602	RB_FOREACH(state, pf_state_tree_id, &tree_id) {
603		state->timeout = PFTM_PURGE;
604#if NPFSYNC
605		state->sync_flags = PFSTATE_NOSYNC;
606#endif
607	}
608	pf_purge_expired_states(pf_status.states);
609
610#if NPFSYNC
611	pfsync_clear_states(pf_status.hostid, NULL);
612#endif
613
614	/* clear source nodes */
615	RB_FOREACH(state, pf_state_tree_id, &tree_id) {
616		state->src_node = NULL;
617		state->nat_src_node = NULL;
618	}
619	RB_FOREACH(node, pf_src_tree, &tree_src_tracking) {
620		node->expire = 1;
621		node->states = 0;
622	}
623	pf_purge_expired_src_nodes();
624
625	/* clear tables */
626	memset(&pt, '\0', sizeof (pt));
627	pfr_clr_tables(&pt.pfrio_table, &pt.pfrio_ndel, pt.pfrio_flags);
628
629	/* destroy anchors */
630	while ((anchor = RB_MIN(pf_anchor_global, &pf_anchors)) != NULL) {
631		for (i = 0; i < PF_RULESET_MAX; i++)
632			if (pf_begin_rules(&ticket, i, anchor->name) == 0)
633				pf_commit_rules(ticket, i, anchor->name);
634	}
635
636	/* destroy main ruleset */
637	pf_remove_if_empty_ruleset(&pf_main_ruleset);
638
639	/* destroy the pools */
640	pool_destroy(&pf_pooladdr_pl);
641#if PF_ALTQ
642	pool_destroy(&pf_altq_pl);
643#endif /* PF_ALTQ */
644	pool_destroy(&pf_state_pl);
645	pool_destroy(&pf_rule_pl);
646	pool_destroy(&pf_src_tree_pl);
647
648	/* destroy subsystems */
649	pf_normalize_destroy();
650	pf_osfp_destroy();
651	pfr_destroy();
652	pfi_destroy();
653}
654#endif
655
656static int
657pfopen(dev_t dev, int flags, int fmt, struct proc *p)
658{
659#pragma unused(flags, fmt, p)
660	if (minor(dev) >= PFDEV_MAX)
661		return (ENXIO);
662
663	if (minor(dev) == PFDEV_PFM) {
664		lck_mtx_lock(pf_lock);
665		if (pfdevcnt != 0) {
666			lck_mtx_unlock(pf_lock);
667			return (EBUSY);
668		}
669		pfdevcnt++;
670		lck_mtx_unlock(pf_lock);
671	}
672	return (0);
673}
674
675static int
676pfclose(dev_t dev, int flags, int fmt, struct proc *p)
677{
678#pragma unused(flags, fmt, p)
679	if (minor(dev) >= PFDEV_MAX)
680		return (ENXIO);
681
682	if (minor(dev) == PFDEV_PFM) {
683		lck_mtx_lock(pf_lock);
684		VERIFY(pfdevcnt > 0);
685		pfdevcnt--;
686		lck_mtx_unlock(pf_lock);
687	}
688	return (0);
689}
690
691static struct pf_pool *
692pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
693    u_int32_t rule_number, u_int8_t r_last, u_int8_t active,
694    u_int8_t check_ticket)
695{
696	struct pf_ruleset	*ruleset;
697	struct pf_rule		*rule;
698	int			 rs_num;
699
700	ruleset = pf_find_ruleset(anchor);
701	if (ruleset == NULL)
702		return (NULL);
703	rs_num = pf_get_ruleset_number(rule_action);
704	if (rs_num >= PF_RULESET_MAX)
705		return (NULL);
706	if (active) {
707		if (check_ticket && ticket !=
708		    ruleset->rules[rs_num].active.ticket)
709			return (NULL);
710		if (r_last)
711			rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
712			    pf_rulequeue);
713		else
714			rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
715	} else {
716		if (check_ticket && ticket !=
717		    ruleset->rules[rs_num].inactive.ticket)
718			return (NULL);
719		if (r_last)
720			rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
721			    pf_rulequeue);
722		else
723			rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
724	}
725	if (!r_last) {
726		while ((rule != NULL) && (rule->nr != rule_number))
727			rule = TAILQ_NEXT(rule, entries);
728	}
729	if (rule == NULL)
730		return (NULL);
731
732	return (&rule->rpool);
733}
734
735static void
736pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
737{
738	struct pf_pooladdr	*mv_pool_pa;
739
740	while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
741		TAILQ_REMOVE(poola, mv_pool_pa, entries);
742		TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
743	}
744}
745
746static void
747pf_empty_pool(struct pf_palist *poola)
748{
749	struct pf_pooladdr	*empty_pool_pa;
750
751	while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
752		pfi_dynaddr_remove(&empty_pool_pa->addr);
753		pf_tbladdr_remove(&empty_pool_pa->addr);
754		pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
755		TAILQ_REMOVE(poola, empty_pool_pa, entries);
756		pool_put(&pf_pooladdr_pl, empty_pool_pa);
757	}
758}
759
760void
761pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
762{
763	if (rulequeue != NULL) {
764		if (rule->states <= 0) {
765			/*
766			 * XXX - we need to remove the table *before* detaching
767			 * the rule to make sure the table code does not delete
768			 * the anchor under our feet.
769			 */
770			pf_tbladdr_remove(&rule->src.addr);
771			pf_tbladdr_remove(&rule->dst.addr);
772			if (rule->overload_tbl)
773				pfr_detach_table(rule->overload_tbl);
774		}
775		TAILQ_REMOVE(rulequeue, rule, entries);
776		rule->entries.tqe_prev = NULL;
777		rule->nr = -1;
778	}
779
780	if (rule->states > 0 || rule->src_nodes > 0 ||
781	    rule->entries.tqe_prev != NULL)
782		return;
783	pf_tag_unref(rule->tag);
784	pf_tag_unref(rule->match_tag);
785#if PF_ALTQ
786	if (altq_allowed) {
787		if (rule->pqid != rule->qid)
788			pf_qid_unref(rule->pqid);
789		pf_qid_unref(rule->qid);
790	}
791#endif /* PF_ALTQ */
792	pf_rtlabel_remove(&rule->src.addr);
793	pf_rtlabel_remove(&rule->dst.addr);
794	pfi_dynaddr_remove(&rule->src.addr);
795	pfi_dynaddr_remove(&rule->dst.addr);
796	if (rulequeue == NULL) {
797		pf_tbladdr_remove(&rule->src.addr);
798		pf_tbladdr_remove(&rule->dst.addr);
799		if (rule->overload_tbl)
800			pfr_detach_table(rule->overload_tbl);
801	}
802	pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
803	pf_anchor_remove(rule);
804	pf_empty_pool(&rule->rpool.list);
805	pool_put(&pf_rule_pl, rule);
806}
807
808static u_int16_t
809tagname2tag(struct pf_tags *head, char *tagname)
810{
811	struct pf_tagname	*tag, *p = NULL;
812	u_int16_t		 new_tagid = 1;
813
814	TAILQ_FOREACH(tag, head, entries)
815		if (strcmp(tagname, tag->name) == 0) {
816			tag->ref++;
817			return (tag->tag);
818		}
819
820	/*
821	 * to avoid fragmentation, we do a linear search from the beginning
822	 * and take the first free slot we find. if there is none or the list
823	 * is empty, append a new entry at the end.
824	 */
825
826	/* new entry */
827	if (!TAILQ_EMPTY(head))
828		for (p = TAILQ_FIRST(head); p != NULL &&
829		    p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
830			new_tagid = p->tag + 1;
831
832	if (new_tagid > TAGID_MAX)
833		return (0);
834
835	/* allocate and fill new struct pf_tagname */
836	tag = _MALLOC(sizeof (*tag), M_TEMP, M_WAITOK|M_ZERO);
837	if (tag == NULL)
838		return (0);
839	strlcpy(tag->name, tagname, sizeof (tag->name));
840	tag->tag = new_tagid;
841	tag->ref++;
842
843	if (p != NULL)	/* insert new entry before p */
844		TAILQ_INSERT_BEFORE(p, tag, entries);
845	else	/* either list empty or no free slot in between */
846		TAILQ_INSERT_TAIL(head, tag, entries);
847
848	return (tag->tag);
849}
850
851static void
852tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
853{
854	struct pf_tagname	*tag;
855
856	TAILQ_FOREACH(tag, head, entries)
857		if (tag->tag == tagid) {
858			strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
859			return;
860		}
861}
862
863static void
864tag_unref(struct pf_tags *head, u_int16_t tag)
865{
866	struct pf_tagname	*p, *next;
867
868	if (tag == 0)
869		return;
870
871	for (p = TAILQ_FIRST(head); p != NULL; p = next) {
872		next = TAILQ_NEXT(p, entries);
873		if (tag == p->tag) {
874			if (--p->ref == 0) {
875				TAILQ_REMOVE(head, p, entries);
876				_FREE(p, M_TEMP);
877			}
878			break;
879		}
880	}
881}
882
883u_int16_t
884pf_tagname2tag(char *tagname)
885{
886	return (tagname2tag(&pf_tags, tagname));
887}
888
889void
890pf_tag2tagname(u_int16_t tagid, char *p)
891{
892	tag2tagname(&pf_tags, tagid, p);
893}
894
895void
896pf_tag_ref(u_int16_t tag)
897{
898	struct pf_tagname *t;
899
900	TAILQ_FOREACH(t, &pf_tags, entries)
901		if (t->tag == tag)
902			break;
903	if (t != NULL)
904		t->ref++;
905}
906
907void
908pf_tag_unref(u_int16_t tag)
909{
910	tag_unref(&pf_tags, tag);
911}
912
913static int
914pf_rtlabel_add(struct pf_addr_wrap *a)
915{
916#pragma unused(a)
917	return (0);
918}
919
920static void
921pf_rtlabel_remove(struct pf_addr_wrap *a)
922{
923#pragma unused(a)
924}
925
926static void
927pf_rtlabel_copyout(struct pf_addr_wrap *a)
928{
929#pragma unused(a)
930}
931
932#if PF_ALTQ
933u_int32_t
934pf_qname2qid(char *qname)
935{
936	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
937
938	return ((u_int32_t)tagname2tag(&pf_qids, qname));
939}
940
941void
942pf_qid2qname(u_int32_t qid, char *p)
943{
944	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
945
946	tag2tagname(&pf_qids, (u_int16_t)qid, p);
947}
948
949void
950pf_qid_unref(u_int32_t qid)
951{
952	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
953
954	tag_unref(&pf_qids, (u_int16_t)qid);
955}
956
957static int
958pf_begin_altq(u_int32_t *ticket)
959{
960	struct pf_altq	*altq;
961	int		 error = 0;
962
963	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
964
965	/* Purge the old altq list */
966	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
967		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
968		if (altq->qname[0] == '\0') {
969			/* detach and destroy the discipline */
970			error = altq_remove(altq);
971		} else
972			pf_qid_unref(altq->qid);
973		pool_put(&pf_altq_pl, altq);
974	}
975	if (error)
976		return (error);
977	*ticket = ++ticket_altqs_inactive;
978	altqs_inactive_open = 1;
979	return (0);
980}
981
982static int
983pf_rollback_altq(u_int32_t ticket)
984{
985	struct pf_altq	*altq;
986	int		 error = 0;
987
988	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
989
990	if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
991		return (0);
992	/* Purge the old altq list */
993	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
994		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
995		if (altq->qname[0] == '\0') {
996			/* detach and destroy the discipline */
997			error = altq_remove(altq);
998		} else
999			pf_qid_unref(altq->qid);
1000		pool_put(&pf_altq_pl, altq);
1001	}
1002	altqs_inactive_open = 0;
1003	return (error);
1004}
1005
1006static int
1007pf_commit_altq(u_int32_t ticket)
1008{
1009	struct pf_altqqueue	*old_altqs;
1010	struct pf_altq		*altq;
1011	int			 err, error = 0;
1012
1013	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
1014
1015	if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
1016		return (EBUSY);
1017
1018	/* swap altqs, keep the old. */
1019	old_altqs = pf_altqs_active;
1020	pf_altqs_active = pf_altqs_inactive;
1021	pf_altqs_inactive = old_altqs;
1022	ticket_altqs_active = ticket_altqs_inactive;
1023
1024	/* Attach new disciplines */
1025	TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1026		if (altq->qname[0] == '\0') {
1027			/* attach the discipline */
1028			error = altq_pfattach(altq);
1029			if (error == 0 && pf_altq_running)
1030				error = pf_enable_altq(altq);
1031			if (error != 0) {
1032				return (error);
1033			}
1034		}
1035	}
1036
1037	/* Purge the old altq list */
1038	while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1039		TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1040		if (altq->qname[0] == '\0') {
1041			/* detach and destroy the discipline */
1042			if (pf_altq_running)
1043				error = pf_disable_altq(altq);
1044			err = altq_pfdetach(altq);
1045			if (err != 0 && error == 0)
1046				error = err;
1047			err = altq_remove(altq);
1048			if (err != 0 && error == 0)
1049				error = err;
1050		} else
1051			pf_qid_unref(altq->qid);
1052		pool_put(&pf_altq_pl, altq);
1053	}
1054
1055	altqs_inactive_open = 0;
1056	return (error);
1057}
1058
1059static int
1060pf_enable_altq(struct pf_altq *altq)
1061{
1062	struct ifnet		*ifp;
1063	struct ifclassq		*ifq;
1064	int			 error = 0;
1065
1066	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
1067
1068	if ((ifp = ifunit(altq->ifname)) == NULL)
1069		return (EINVAL);
1070
1071	ifq = &ifp->if_snd;
1072	IFCQ_LOCK(ifq);
1073	if (IFCQ_ALTQ(ifq)->altq_type != ALTQT_NONE)
1074		error = altq_enable(IFCQ_ALTQ(ifq));
1075
1076	/* set or clear tokenbucket regulator */
1077	if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(IFCQ_ALTQ(ifq))) {
1078		struct tb_profile tb = { 0, 0, 0 };
1079
1080		if (altq->aflags & PF_ALTQF_TBR) {
1081			if (altq->bwtype != PF_ALTQ_BW_ABSOLUTE &&
1082			    altq->bwtype != PF_ALTQ_BW_PERCENT) {
1083				error = EINVAL;
1084			} else {
1085				if (altq->bwtype == PF_ALTQ_BW_ABSOLUTE)
1086					tb.rate = altq->ifbandwidth;
1087				else
1088					tb.percent = altq->ifbandwidth;
1089				tb.depth = altq->tbrsize;
1090				error = ifclassq_tbr_set(ifq, &tb, TRUE);
1091			}
1092		} else if (IFCQ_TBR_IS_ENABLED(ifq)) {
1093			error = ifclassq_tbr_set(ifq, &tb, TRUE);
1094		}
1095	}
1096	IFCQ_UNLOCK(ifq);
1097
1098	return (error);
1099}
1100
1101static int
1102pf_disable_altq(struct pf_altq *altq)
1103{
1104	struct ifnet		*ifp;
1105	struct ifclassq		*ifq;
1106	int			 error;
1107
1108	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
1109
1110	if ((ifp = ifunit(altq->ifname)) == NULL)
1111		return (EINVAL);
1112
1113	/*
1114	 * when the discipline is no longer referenced, it was overridden
1115	 * by a new one.  if so, just return.
1116	 */
1117	ifq = &ifp->if_snd;
1118	IFCQ_LOCK(ifq);
1119	if (altq->altq_disc != IFCQ_ALTQ(ifq)->altq_disc) {
1120		IFCQ_UNLOCK(ifq);
1121		return (0);
1122	}
1123
1124	error = altq_disable(IFCQ_ALTQ(ifq));
1125
1126	if (error == 0 && IFCQ_TBR_IS_ENABLED(ifq)) {
1127		/* clear tokenbucket regulator */
1128		struct tb_profile  tb = { 0, 0, 0 };
1129		error = ifclassq_tbr_set(ifq, &tb, TRUE);
1130	}
1131	IFCQ_UNLOCK(ifq);
1132
1133	return (error);
1134}
1135
1136static void
1137pf_altq_copyin(struct pf_altq *src, struct pf_altq *dst)
1138{
1139	bcopy(src, dst, sizeof (struct pf_altq));
1140
1141	dst->ifname[sizeof (dst->ifname) - 1] = '\0';
1142	dst->qname[sizeof (dst->qname) - 1] = '\0';
1143	dst->parent[sizeof (dst->parent) - 1] = '\0';
1144	dst->altq_disc = NULL;
1145	dst->entries.tqe_next = NULL;
1146	dst->entries.tqe_prev = NULL;
1147}
1148
1149static void
1150pf_altq_copyout(struct pf_altq *src, struct pf_altq *dst)
1151{
1152	struct pf_altq pa;
1153
1154	bcopy(src, &pa, sizeof (struct pf_altq));
1155	pa.altq_disc = NULL;
1156	pa.entries.tqe_next = NULL;
1157	pa.entries.tqe_prev = NULL;
1158	bcopy(&pa, dst, sizeof (struct pf_altq));
1159}
1160#endif /* PF_ALTQ */
1161
1162static int
1163pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
1164{
1165	struct pf_ruleset	*rs;
1166	struct pf_rule		*rule;
1167
1168	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
1169		return (EINVAL);
1170	rs = pf_find_or_create_ruleset(anchor);
1171	if (rs == NULL)
1172		return (EINVAL);
1173	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
1174		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
1175		rs->rules[rs_num].inactive.rcount--;
1176	}
1177	*ticket = ++rs->rules[rs_num].inactive.ticket;
1178	rs->rules[rs_num].inactive.open = 1;
1179	return (0);
1180}
1181
1182static int
1183pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
1184{
1185	struct pf_ruleset	*rs;
1186	struct pf_rule		*rule;
1187
1188	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
1189		return (EINVAL);
1190	rs = pf_find_ruleset(anchor);
1191	if (rs == NULL || !rs->rules[rs_num].inactive.open ||
1192	    rs->rules[rs_num].inactive.ticket != ticket)
1193		return (0);
1194	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
1195		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
1196		rs->rules[rs_num].inactive.rcount--;
1197	}
1198	rs->rules[rs_num].inactive.open = 0;
1199	return (0);
1200}
1201
1202#define	PF_MD5_UPD(st, elm)						\
1203	MD5Update(ctx, (u_int8_t *)&(st)->elm, sizeof ((st)->elm))
1204
1205#define	PF_MD5_UPD_STR(st, elm)						\
1206	MD5Update(ctx, (u_int8_t *)(st)->elm, strlen((st)->elm))
1207
1208#define	PF_MD5_UPD_HTONL(st, elm, stor) do {				\
1209	(stor) = htonl((st)->elm);					\
1210	MD5Update(ctx, (u_int8_t *)&(stor), sizeof (u_int32_t));	\
1211} while (0)
1212
1213#define	PF_MD5_UPD_HTONS(st, elm, stor) do {				\
1214	(stor) = htons((st)->elm);					\
1215	MD5Update(ctx, (u_int8_t *)&(stor), sizeof (u_int16_t));	\
1216} while (0)
1217
1218static void
1219pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr, u_int8_t proto)
1220{
1221	PF_MD5_UPD(pfr, addr.type);
1222	switch (pfr->addr.type) {
1223	case PF_ADDR_DYNIFTL:
1224		PF_MD5_UPD(pfr, addr.v.ifname);
1225		PF_MD5_UPD(pfr, addr.iflags);
1226		break;
1227	case PF_ADDR_TABLE:
1228		PF_MD5_UPD(pfr, addr.v.tblname);
1229		break;
1230	case PF_ADDR_ADDRMASK:
1231		/* XXX ignore af? */
1232		PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
1233		PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
1234		break;
1235	case PF_ADDR_RTLABEL:
1236		PF_MD5_UPD(pfr, addr.v.rtlabelname);
1237		break;
1238	}
1239
1240	switch (proto) {
1241	case IPPROTO_TCP:
1242	case IPPROTO_UDP:
1243		PF_MD5_UPD(pfr, xport.range.port[0]);
1244		PF_MD5_UPD(pfr, xport.range.port[1]);
1245		PF_MD5_UPD(pfr, xport.range.op);
1246		break;
1247
1248	default:
1249		break;
1250	}
1251
1252	PF_MD5_UPD(pfr, neg);
1253}
1254
1255static void
1256pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
1257{
1258	u_int16_t x;
1259	u_int32_t y;
1260
1261	pf_hash_rule_addr(ctx, &rule->src, rule->proto);
1262	pf_hash_rule_addr(ctx, &rule->dst, rule->proto);
1263	PF_MD5_UPD_STR(rule, label);
1264	PF_MD5_UPD_STR(rule, ifname);
1265	PF_MD5_UPD_STR(rule, match_tagname);
1266	PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
1267	PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
1268	PF_MD5_UPD_HTONL(rule, prob, y);
1269	PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
1270	PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
1271	PF_MD5_UPD(rule, uid.op);
1272	PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
1273	PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
1274	PF_MD5_UPD(rule, gid.op);
1275	PF_MD5_UPD_HTONL(rule, rule_flag, y);
1276	PF_MD5_UPD(rule, action);
1277	PF_MD5_UPD(rule, direction);
1278	PF_MD5_UPD(rule, af);
1279	PF_MD5_UPD(rule, quick);
1280	PF_MD5_UPD(rule, ifnot);
1281	PF_MD5_UPD(rule, match_tag_not);
1282	PF_MD5_UPD(rule, natpass);
1283	PF_MD5_UPD(rule, keep_state);
1284	PF_MD5_UPD(rule, proto);
1285	PF_MD5_UPD(rule, type);
1286	PF_MD5_UPD(rule, code);
1287	PF_MD5_UPD(rule, flags);
1288	PF_MD5_UPD(rule, flagset);
1289	PF_MD5_UPD(rule, allow_opts);
1290	PF_MD5_UPD(rule, rt);
1291	PF_MD5_UPD(rule, tos);
1292}
1293
1294static int
1295pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
1296{
1297	struct pf_ruleset	*rs;
1298	struct pf_rule		*rule, **old_array, *r;
1299	struct pf_rulequeue	*old_rules;
1300	int			 error;
1301	u_int32_t		 old_rcount;
1302
1303	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
1304
1305	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
1306		return (EINVAL);
1307	rs = pf_find_ruleset(anchor);
1308	if (rs == NULL || !rs->rules[rs_num].inactive.open ||
1309	    ticket != rs->rules[rs_num].inactive.ticket)
1310		return (EBUSY);
1311
1312	/* Calculate checksum for the main ruleset */
1313	if (rs == &pf_main_ruleset) {
1314		error = pf_setup_pfsync_matching(rs);
1315		if (error != 0)
1316			return (error);
1317	}
1318
1319	/* Swap rules, keep the old. */
1320	old_rules = rs->rules[rs_num].active.ptr;
1321	old_rcount = rs->rules[rs_num].active.rcount;
1322	old_array = rs->rules[rs_num].active.ptr_array;
1323
1324	if(old_rcount != 0) {
1325		r = TAILQ_FIRST(rs->rules[rs_num].active.ptr);
1326		while (r) {
1327			if (r->rule_flag & PFRULE_PFM)
1328				pffwrules--;
1329			r = TAILQ_NEXT(r, entries);
1330		}
1331	}
1332
1333
1334	rs->rules[rs_num].active.ptr =
1335	    rs->rules[rs_num].inactive.ptr;
1336	rs->rules[rs_num].active.ptr_array =
1337	    rs->rules[rs_num].inactive.ptr_array;
1338	rs->rules[rs_num].active.rcount =
1339	    rs->rules[rs_num].inactive.rcount;
1340	rs->rules[rs_num].inactive.ptr = old_rules;
1341	rs->rules[rs_num].inactive.ptr_array = old_array;
1342	rs->rules[rs_num].inactive.rcount = old_rcount;
1343
1344	rs->rules[rs_num].active.ticket =
1345	    rs->rules[rs_num].inactive.ticket;
1346	pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
1347
1348
1349	/* Purge the old rule list. */
1350	while ((rule = TAILQ_FIRST(old_rules)) != NULL)
1351		pf_rm_rule(old_rules, rule);
1352	if (rs->rules[rs_num].inactive.ptr_array)
1353		_FREE(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
1354	rs->rules[rs_num].inactive.ptr_array = NULL;
1355	rs->rules[rs_num].inactive.rcount = 0;
1356	rs->rules[rs_num].inactive.open = 0;
1357	pf_remove_if_empty_ruleset(rs);
1358	return (0);
1359}
1360
1361static void
1362pf_rule_copyin(struct pf_rule *src, struct pf_rule *dst, struct proc *p,
1363    int minordev)
1364{
1365	bcopy(src, dst, sizeof (struct pf_rule));
1366
1367	dst->label[sizeof (dst->label) - 1] = '\0';
1368	dst->ifname[sizeof (dst->ifname) - 1] = '\0';
1369	dst->qname[sizeof (dst->qname) - 1] = '\0';
1370	dst->pqname[sizeof (dst->pqname) - 1] = '\0';
1371	dst->tagname[sizeof (dst->tagname) - 1] = '\0';
1372	dst->match_tagname[sizeof (dst->match_tagname) - 1] = '\0';
1373	dst->overload_tblname[sizeof (dst->overload_tblname) - 1] = '\0';
1374
1375	dst->cuid = kauth_cred_getuid(p->p_ucred);
1376	dst->cpid = p->p_pid;
1377
1378	dst->anchor = NULL;
1379	dst->kif = NULL;
1380	dst->overload_tbl = NULL;
1381
1382	TAILQ_INIT(&dst->rpool.list);
1383	dst->rpool.cur = NULL;
1384
1385	/* initialize refcounting */
1386	dst->states = 0;
1387	dst->src_nodes = 0;
1388
1389	dst->entries.tqe_prev = NULL;
1390	dst->entries.tqe_next = NULL;
1391	if ((uint8_t)minordev == PFDEV_PFM)
1392		dst->rule_flag |= PFRULE_PFM;
1393}
1394
1395static void
1396pf_rule_copyout(struct pf_rule *src, struct pf_rule *dst)
1397{
1398	bcopy(src, dst, sizeof (struct pf_rule));
1399
1400	dst->anchor = NULL;
1401	dst->kif = NULL;
1402	dst->overload_tbl = NULL;
1403
1404	TAILQ_INIT(&dst->rpool.list);
1405	dst->rpool.cur = NULL;
1406
1407	dst->entries.tqe_prev = NULL;
1408	dst->entries.tqe_next = NULL;
1409}
1410
1411static void
1412pf_state_export(struct pfsync_state *sp, struct pf_state_key *sk,
1413    struct pf_state *s)
1414{
1415	uint64_t secs = pf_time_second();
1416	bzero(sp, sizeof (struct pfsync_state));
1417
1418	/* copy from state key */
1419	sp->lan.addr = sk->lan.addr;
1420	sp->lan.xport = sk->lan.xport;
1421	sp->gwy.addr = sk->gwy.addr;
1422	sp->gwy.xport = sk->gwy.xport;
1423	sp->ext.addr = sk->ext.addr;
1424	sp->ext.xport = sk->ext.xport;
1425	sp->proto_variant = sk->proto_variant;
1426	sp->tag = s->tag;
1427	sp->proto = sk->proto;
1428	sp->af = sk->af;
1429	sp->direction = sk->direction;
1430	sp->flowhash = sk->flowhash;
1431
1432	/* copy from state */
1433	memcpy(&sp->id, &s->id, sizeof (sp->id));
1434	sp->creatorid = s->creatorid;
1435	strlcpy(sp->ifname, s->kif->pfik_name, sizeof (sp->ifname));
1436	pf_state_peer_to_pfsync(&s->src, &sp->src);
1437	pf_state_peer_to_pfsync(&s->dst, &sp->dst);
1438
1439	sp->rule = s->rule.ptr->nr;
1440	sp->nat_rule = (s->nat_rule.ptr == NULL) ?
1441	    (unsigned)-1 : s->nat_rule.ptr->nr;
1442	sp->anchor = (s->anchor.ptr == NULL) ?
1443	    (unsigned)-1 : s->anchor.ptr->nr;
1444
1445	pf_state_counter_to_pfsync(s->bytes[0], sp->bytes[0]);
1446	pf_state_counter_to_pfsync(s->bytes[1], sp->bytes[1]);
1447	pf_state_counter_to_pfsync(s->packets[0], sp->packets[0]);
1448	pf_state_counter_to_pfsync(s->packets[1], sp->packets[1]);
1449	sp->creation = secs - s->creation;
1450	sp->expire = pf_state_expires(s);
1451	sp->log = s->log;
1452	sp->allow_opts = s->allow_opts;
1453	sp->timeout = s->timeout;
1454
1455	if (s->src_node)
1456		sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
1457	if (s->nat_src_node)
1458		sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
1459
1460	if (sp->expire > secs)
1461		sp->expire -= secs;
1462	else
1463		sp->expire = 0;
1464
1465}
1466
1467static void
1468pf_state_import(struct pfsync_state *sp, struct pf_state_key *sk,
1469    struct pf_state *s)
1470{
1471	/* copy to state key */
1472	sk->lan.addr = sp->lan.addr;
1473	sk->lan.xport = sp->lan.xport;
1474	sk->gwy.addr = sp->gwy.addr;
1475	sk->gwy.xport = sp->gwy.xport;
1476	sk->ext.addr = sp->ext.addr;
1477	sk->ext.xport = sp->ext.xport;
1478	sk->proto_variant = sp->proto_variant;
1479	s->tag = sp->tag;
1480	sk->proto = sp->proto;
1481	sk->af = sp->af;
1482	sk->direction = sp->direction;
1483	sk->flowhash = pf_calc_state_key_flowhash(sk);
1484
1485	/* copy to state */
1486	memcpy(&s->id, &sp->id, sizeof (sp->id));
1487	s->creatorid = sp->creatorid;
1488	pf_state_peer_from_pfsync(&sp->src, &s->src);
1489	pf_state_peer_from_pfsync(&sp->dst, &s->dst);
1490
1491	s->rule.ptr = &pf_default_rule;
1492	s->nat_rule.ptr = NULL;
1493	s->anchor.ptr = NULL;
1494	s->rt_kif = NULL;
1495	s->creation = pf_time_second();
1496	s->expire = pf_time_second();
1497	if (sp->expire > 0)
1498		s->expire -= pf_default_rule.timeout[sp->timeout] - sp->expire;
1499	s->pfsync_time = 0;
1500	s->packets[0] = s->packets[1] = 0;
1501	s->bytes[0] = s->bytes[1] = 0;
1502}
1503
1504static void
1505pf_pooladdr_copyin(struct pf_pooladdr *src, struct pf_pooladdr *dst)
1506{
1507	bcopy(src, dst, sizeof (struct pf_pooladdr));
1508
1509	dst->entries.tqe_prev = NULL;
1510	dst->entries.tqe_next = NULL;
1511	dst->ifname[sizeof (dst->ifname) - 1] = '\0';
1512	dst->kif = NULL;
1513}
1514
1515static void
1516pf_pooladdr_copyout(struct pf_pooladdr *src, struct pf_pooladdr *dst)
1517{
1518	bcopy(src, dst, sizeof (struct pf_pooladdr));
1519
1520	dst->entries.tqe_prev = NULL;
1521	dst->entries.tqe_next = NULL;
1522	dst->kif = NULL;
1523}
1524
1525static int
1526pf_setup_pfsync_matching(struct pf_ruleset *rs)
1527{
1528	MD5_CTX			 ctx;
1529	struct pf_rule		*rule;
1530	int			 rs_cnt;
1531	u_int8_t		 digest[PF_MD5_DIGEST_LENGTH];
1532
1533	MD5Init(&ctx);
1534	for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
1535		/* XXX PF_RULESET_SCRUB as well? */
1536		if (rs_cnt == PF_RULESET_SCRUB)
1537			continue;
1538
1539		if (rs->rules[rs_cnt].inactive.ptr_array)
1540			_FREE(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
1541		rs->rules[rs_cnt].inactive.ptr_array = NULL;
1542
1543		if (rs->rules[rs_cnt].inactive.rcount) {
1544			rs->rules[rs_cnt].inactive.ptr_array =
1545			    _MALLOC(sizeof (caddr_t) *
1546			    rs->rules[rs_cnt].inactive.rcount,
1547			    M_TEMP, M_WAITOK);
1548
1549			if (!rs->rules[rs_cnt].inactive.ptr_array)
1550				return (ENOMEM);
1551		}
1552
1553		TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
1554		    entries) {
1555			pf_hash_rule(&ctx, rule);
1556			(rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
1557		}
1558	}
1559
1560	MD5Final(digest, &ctx);
1561	memcpy(pf_status.pf_chksum, digest, sizeof (pf_status.pf_chksum));
1562	return (0);
1563}
1564
1565static void
1566pf_start(void)
1567{
1568	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
1569
1570	VERIFY(pf_is_enabled == 0);
1571
1572	pf_is_enabled = 1;
1573	pf_status.running = 1;
1574	pf_status.since = pf_calendar_time_second();
1575	if (pf_status.stateid == 0) {
1576		pf_status.stateid = pf_time_second();
1577		pf_status.stateid = pf_status.stateid << 32;
1578	}
1579	wakeup(pf_purge_thread_fn);
1580	DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
1581}
1582
1583static void
1584pf_stop(void)
1585{
1586	lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED);
1587
1588	VERIFY(pf_is_enabled);
1589
1590	pf_status.running = 0;
1591	pf_is_enabled = 0;
1592	pf_status.since = pf_calendar_time_second();
1593	wakeup(pf_purge_thread_fn);
1594	DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
1595}
1596
1597static int
1598pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
1599{
1600#pragma unused(dev)
1601	int p64 = proc_is64bit(p);
1602	int error = 0;
1603	int minordev = minor(dev);
1604
1605	if (kauth_cred_issuser(kauth_cred_get()) == 0)
1606		return (EPERM);
1607
1608	/* XXX keep in sync with switch() below */
1609	if (securelevel > 1)
1610		switch (cmd) {
1611		case DIOCGETRULES:
1612		case DIOCGETRULE:
1613		case DIOCGETADDRS:
1614		case DIOCGETADDR:
1615		case DIOCGETSTATE:
1616		case DIOCSETSTATUSIF:
1617		case DIOCGETSTATUS:
1618		case DIOCCLRSTATUS:
1619		case DIOCNATLOOK:
1620		case DIOCSETDEBUG:
1621		case DIOCGETSTATES:
1622		case DIOCINSERTRULE:
1623		case DIOCDELETERULE:
1624		case DIOCGETTIMEOUT:
1625		case DIOCCLRRULECTRS:
1626		case DIOCGETLIMIT:
1627		case DIOCGETALTQS:
1628		case DIOCGETALTQ:
1629		case DIOCGETQSTATS:
1630		case DIOCGETRULESETS:
1631		case DIOCGETRULESET:
1632		case DIOCRGETTABLES:
1633		case DIOCRGETTSTATS:
1634		case DIOCRCLRTSTATS:
1635		case DIOCRCLRADDRS:
1636		case DIOCRADDADDRS:
1637		case DIOCRDELADDRS:
1638		case DIOCRSETADDRS:
1639		case DIOCRGETADDRS:
1640		case DIOCRGETASTATS:
1641		case DIOCRCLRASTATS:
1642		case DIOCRTSTADDRS:
1643		case DIOCOSFPGET:
1644		case DIOCGETSRCNODES:
1645		case DIOCCLRSRCNODES:
1646		case DIOCIGETIFACES:
1647		case DIOCGIFSPEED:
1648		case DIOCSETIFFLAG:
1649		case DIOCCLRIFFLAG:
1650			break;
1651		case DIOCRCLRTABLES:
1652		case DIOCRADDTABLES:
1653		case DIOCRDELTABLES:
1654		case DIOCRSETTFLAGS: {
1655			int pfrio_flags;
1656
1657			bcopy(&((struct pfioc_table *)(void *)addr)->
1658			    pfrio_flags, &pfrio_flags, sizeof (pfrio_flags));
1659
1660			if (pfrio_flags & PFR_FLAG_DUMMY)
1661				break; /* dummy operation ok */
1662			return (EPERM);
1663		}
1664		default:
1665			return (EPERM);
1666		}
1667
1668	if (!(flags & FWRITE))
1669		switch (cmd) {
1670		case DIOCSTART:
1671		case DIOCSTARTREF:
1672		case DIOCSTOP:
1673		case DIOCSTOPREF:
1674		case DIOCGETSTARTERS:
1675		case DIOCGETRULES:
1676		case DIOCGETADDRS:
1677		case DIOCGETADDR:
1678		case DIOCGETSTATE:
1679		case DIOCGETSTATUS:
1680		case DIOCGETSTATES:
1681		case DIOCINSERTRULE:
1682		case DIOCDELETERULE:
1683		case DIOCGETTIMEOUT:
1684		case DIOCGETLIMIT:
1685		case DIOCGETALTQS:
1686		case DIOCGETALTQ:
1687		case DIOCGETQSTATS:
1688		case DIOCGETRULESETS:
1689		case DIOCGETRULESET:
1690		case DIOCNATLOOK:
1691		case DIOCRGETTABLES:
1692		case DIOCRGETTSTATS:
1693		case DIOCRGETADDRS:
1694		case DIOCRGETASTATS:
1695		case DIOCRTSTADDRS:
1696		case DIOCOSFPGET:
1697		case DIOCGETSRCNODES:
1698		case DIOCIGETIFACES:
1699		case DIOCGIFSPEED:
1700			break;
1701		case DIOCRCLRTABLES:
1702		case DIOCRADDTABLES:
1703		case DIOCRDELTABLES:
1704		case DIOCRCLRTSTATS:
1705		case DIOCRCLRADDRS:
1706		case DIOCRADDADDRS:
1707		case DIOCRDELADDRS:
1708		case DIOCRSETADDRS:
1709		case DIOCRSETTFLAGS: {
1710			int pfrio_flags;
1711
1712			bcopy(&((struct pfioc_table *)(void *)addr)->
1713			    pfrio_flags, &pfrio_flags, sizeof (pfrio_flags));
1714
1715			if (pfrio_flags & PFR_FLAG_DUMMY) {
1716				flags |= FWRITE; /* need write lock for dummy */
1717				break; /* dummy operation ok */
1718			}
1719			return (EACCES);
1720		}
1721		case DIOCGETRULE: {
1722			u_int32_t action;
1723
1724			bcopy(&((struct pfioc_rule *)(void *)addr)->action,
1725			    &action, sizeof (action));
1726
1727			if (action == PF_GET_CLR_CNTR)
1728				return (EACCES);
1729			break;
1730		}
1731		default:
1732			return (EACCES);
1733		}
1734
1735#if PF_ALTQ
1736	switch (cmd) {
1737	case DIOCSTARTALTQ:
1738	case DIOCSTOPALTQ:
1739	case DIOCADDALTQ:
1740	case DIOCGETALTQS:
1741	case DIOCGETALTQ:
1742	case DIOCCHANGEALTQ:
1743	case DIOCGETQSTATS:
1744		/* fail if ALTQ is disabled */
1745		if (!altq_allowed)
1746			return (ENODEV);
1747		break;
1748	}
1749#endif /* PF_ALTQ */
1750
1751	if (flags & FWRITE)
1752		lck_rw_lock_exclusive(pf_perim_lock);
1753	else
1754		lck_rw_lock_shared(pf_perim_lock);
1755
1756	lck_mtx_lock(pf_lock);
1757
1758	switch (cmd) {
1759
1760	case DIOCSTART:
1761		if (pf_status.running) {
1762			/*
1763			 * Increment the reference for a simple -e enable, so
1764			 * that even if other processes drop their references,
1765			 * pf will still be available to processes that turned
1766			 * it on without taking a reference
1767			 */
1768			if (nr_tokens == pf_enabled_ref_count) {
1769				pf_enabled_ref_count++;
1770				VERIFY(pf_enabled_ref_count != 0);
1771			}
1772			error = EEXIST;
1773		} else if (pf_purge_thread == NULL) {
1774			error = ENOMEM;
1775		} else {
1776			pf_start();
1777			pf_enabled_ref_count++;
1778			VERIFY(pf_enabled_ref_count != 0);
1779		}
1780		break;
1781
1782	case DIOCSTARTREF:		/* u_int64_t */
1783		if (pf_purge_thread == NULL) {
1784			error = ENOMEM;
1785		} else {
1786			u_int64_t token;
1787
1788			/* small enough to be on stack */
1789			if ((token = generate_token(p)) != 0) {
1790				if (pf_is_enabled == 0) {
1791					pf_start();
1792				}
1793				pf_enabled_ref_count++;
1794				VERIFY(pf_enabled_ref_count != 0);
1795			} else {
1796				error = ENOMEM;
1797				DPFPRINTF(PF_DEBUG_URGENT,
1798				    ("pf: unable to generate token\n"));
1799			}
1800			bcopy(&token, addr, sizeof (token));
1801		}
1802		break;
1803
1804	case DIOCSTOP:
1805		if (!pf_status.running) {
1806			error = ENOENT;
1807		} else {
1808			pf_stop();
1809			pf_enabled_ref_count = 0;
1810			invalidate_all_tokens();
1811		}
1812		break;
1813
1814	case DIOCSTOPREF:		/* struct pfioc_remove_token */
1815		if (!pf_status.running) {
1816			error = ENOENT;
1817		} else {
1818			struct pfioc_remove_token pfrt;
1819
1820			/* small enough to be on stack */
1821			bcopy(addr, &pfrt, sizeof (pfrt));
1822			if ((error = remove_token(&pfrt)) == 0) {
1823				VERIFY(pf_enabled_ref_count != 0);
1824				pf_enabled_ref_count--;
1825				/* return currently held references */
1826				pfrt.refcount = pf_enabled_ref_count;
1827				DPFPRINTF(PF_DEBUG_MISC,
1828				    ("pf: enabled refcount decremented\n"));
1829			} else {
1830				error = EINVAL;
1831				DPFPRINTF(PF_DEBUG_URGENT,
1832				    ("pf: token mismatch\n"));
1833			}
1834			bcopy(&pfrt, addr, sizeof (pfrt));
1835
1836			if (error == 0 && pf_enabled_ref_count == 0)
1837				pf_stop();
1838		}
1839		break;
1840
1841	case DIOCGETSTARTERS: {		/* struct pfioc_tokens */
1842		PFIOCX_STRUCT_DECL(pfioc_tokens);
1843
1844		PFIOCX_STRUCT_BEGIN(addr, pfioc_tokens, error = ENOMEM; break;);
1845		error = pfioctl_ioc_tokens(cmd,
1846		    PFIOCX_STRUCT_ADDR32(pfioc_tokens),
1847		    PFIOCX_STRUCT_ADDR64(pfioc_tokens), p);
1848		PFIOCX_STRUCT_END(pfioc_tokens, addr);
1849		break;
1850	}
1851
1852	case DIOCADDRULE:		/* struct pfioc_rule */
1853	case DIOCGETRULES:		/* struct pfioc_rule */
1854	case DIOCGETRULE:		/* struct pfioc_rule */
1855	case DIOCCHANGERULE:		/* struct pfioc_rule */
1856	case DIOCINSERTRULE:		/* struct pfioc_rule */
1857	case DIOCDELETERULE: {		/* struct pfioc_rule */
1858		struct pfioc_rule *pr = NULL;
1859
1860		PFIOC_STRUCT_BEGIN(addr, pr, error = ENOMEM; break;);
1861		error = pfioctl_ioc_rule(cmd, minordev, pr, p);
1862		PFIOC_STRUCT_END(pr, addr);
1863		break;
1864	}
1865
1866	case DIOCCLRSTATES:		/* struct pfioc_state_kill */
1867	case DIOCKILLSTATES: {		/* struct pfioc_state_kill */
1868		struct pfioc_state_kill *psk = NULL;
1869
1870		PFIOC_STRUCT_BEGIN(addr, psk, error = ENOMEM; break;);
1871		error = pfioctl_ioc_state_kill(cmd, psk, p);
1872		PFIOC_STRUCT_END(psk, addr);
1873		break;
1874	}
1875
1876	case DIOCADDSTATE:		/* struct pfioc_state */
1877	case DIOCGETSTATE: {		/* struct pfioc_state */
1878		struct pfioc_state *ps = NULL;
1879
1880		PFIOC_STRUCT_BEGIN(addr, ps, error = ENOMEM; break;);
1881		error = pfioctl_ioc_state(cmd, ps, p);
1882		PFIOC_STRUCT_END(ps, addr);
1883		break;
1884	}
1885
1886	case DIOCGETSTATES: {		/* struct pfioc_states */
1887		PFIOCX_STRUCT_DECL(pfioc_states);
1888
1889		PFIOCX_STRUCT_BEGIN(addr, pfioc_states, error = ENOMEM; break;);
1890		error = pfioctl_ioc_states(cmd,
1891		    PFIOCX_STRUCT_ADDR32(pfioc_states),
1892		    PFIOCX_STRUCT_ADDR64(pfioc_states), p);
1893		PFIOCX_STRUCT_END(pfioc_states, addr);
1894		break;
1895	}
1896
1897	case DIOCGETSTATUS: {		/* struct pf_status */
1898		struct pf_status *s = NULL;
1899
1900		PFIOC_STRUCT_BEGIN(&pf_status, s, error = ENOMEM; break;);
1901		pfi_update_status(s->ifname, s);
1902		PFIOC_STRUCT_END(s, addr);
1903		break;
1904	}
1905
1906	case DIOCSETSTATUSIF: {		/* struct pfioc_if */
1907		struct pfioc_if	*pi = (struct pfioc_if *)(void *)addr;
1908
1909		/* OK for unaligned accesses */
1910		if (pi->ifname[0] == 0) {
1911			bzero(pf_status.ifname, IFNAMSIZ);
1912			break;
1913		}
1914		strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ);
1915		break;
1916	}
1917
1918	case DIOCCLRSTATUS: {
1919		bzero(pf_status.counters, sizeof (pf_status.counters));
1920		bzero(pf_status.fcounters, sizeof (pf_status.fcounters));
1921		bzero(pf_status.scounters, sizeof (pf_status.scounters));
1922		pf_status.since = pf_calendar_time_second();
1923		if (*pf_status.ifname)
1924			pfi_update_status(pf_status.ifname, NULL);
1925		break;
1926	}
1927
1928	case DIOCNATLOOK: {		/* struct pfioc_natlook */
1929		struct pfioc_natlook *pnl = NULL;
1930
1931		PFIOC_STRUCT_BEGIN(addr, pnl, error = ENOMEM; break;);
1932		error = pfioctl_ioc_natlook(cmd, pnl, p);
1933		PFIOC_STRUCT_END(pnl, addr);
1934		break;
1935	}
1936
1937	case DIOCSETTIMEOUT:		/* struct pfioc_tm */
1938	case DIOCGETTIMEOUT: {		/* struct pfioc_tm */
1939		struct pfioc_tm	pt;
1940
1941		/* small enough to be on stack */
1942		bcopy(addr, &pt, sizeof (pt));
1943		error = pfioctl_ioc_tm(cmd, &pt, p);
1944		bcopy(&pt, addr, sizeof (pt));
1945		break;
1946	}
1947
1948	case DIOCGETLIMIT:		/* struct pfioc_limit */
1949	case DIOCSETLIMIT: {		/* struct pfioc_limit */
1950		struct pfioc_limit pl;
1951
1952		/* small enough to be on stack */
1953		bcopy(addr, &pl, sizeof (pl));
1954		error = pfioctl_ioc_limit(cmd, &pl, p);
1955		bcopy(&pl, addr, sizeof (pl));
1956		break;
1957	}
1958
1959	case DIOCSETDEBUG: {		/* u_int32_t */
1960		bcopy(addr, &pf_status.debug, sizeof (u_int32_t));
1961		break;
1962	}
1963
1964	case DIOCCLRRULECTRS: {
1965		/* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
1966		struct pf_ruleset	*ruleset = &pf_main_ruleset;
1967		struct pf_rule		*rule;
1968
1969		TAILQ_FOREACH(rule,
1970		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
1971			rule->evaluations = 0;
1972			rule->packets[0] = rule->packets[1] = 0;
1973			rule->bytes[0] = rule->bytes[1] = 0;
1974		}
1975		break;
1976	}
1977
1978	case DIOCGIFSPEED: {
1979		struct pf_ifspeed *psp = (struct pf_ifspeed *)(void *)addr;
1980		struct pf_ifspeed ps;
1981		struct ifnet *ifp;
1982		u_int64_t baudrate;
1983
1984		if (psp->ifname[0] != '\0') {
1985			/* Can we completely trust user-land? */
1986			strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
1987			ps.ifname[IFNAMSIZ - 1] = '\0';
1988			ifp = ifunit(ps.ifname);
1989			if (ifp != NULL) {
1990				baudrate = ifp->if_output_bw.max_bw;
1991				bcopy(&baudrate, &psp->baudrate,
1992				    sizeof (baudrate));
1993			} else {
1994				error = EINVAL;
1995			}
1996		} else {
1997			error = EINVAL;
1998		}
1999		break;
2000	}
2001
2002#if PF_ALTQ
2003	case DIOCSTARTALTQ: {
2004		struct pf_altq		*altq;
2005
2006		VERIFY(altq_allowed);
2007		/* enable all altq interfaces on active list */
2008		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2009			if (altq->qname[0] == '\0') {
2010				error = pf_enable_altq(altq);
2011				if (error != 0)
2012					break;
2013			}
2014		}
2015		if (error == 0)
2016			pf_altq_running = 1;
2017		DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
2018		break;
2019	}
2020
2021	case DIOCSTOPALTQ: {
2022		struct pf_altq		*altq;
2023
2024		VERIFY(altq_allowed);
2025		/* disable all altq interfaces on active list */
2026		TAILQ_FOREACH(altq, pf_altqs_active, entries) {
2027			if (altq->qname[0] == '\0') {
2028				error = pf_disable_altq(altq);
2029				if (error != 0)
2030					break;
2031			}
2032		}
2033		if (error == 0)
2034			pf_altq_running = 0;
2035		DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
2036		break;
2037	}
2038
2039	case DIOCADDALTQ: {		/* struct pfioc_altq */
2040		struct pfioc_altq	*pa = (struct pfioc_altq *)(void *)addr;
2041		struct pf_altq		*altq, *a;
2042		u_int32_t		ticket;
2043
2044		VERIFY(altq_allowed);
2045		bcopy(&pa->ticket, &ticket, sizeof (ticket));
2046		if (ticket != ticket_altqs_inactive) {
2047			error = EBUSY;
2048			break;
2049		}
2050		altq = pool_get(&pf_altq_pl, PR_WAITOK);
2051		if (altq == NULL) {
2052			error = ENOMEM;
2053			break;
2054		}
2055		pf_altq_copyin(&pa->altq, altq);
2056
2057		/*
2058		 * if this is for a queue, find the discipline and
2059		 * copy the necessary fields
2060		 */
2061		if (altq->qname[0] != '\0') {
2062			if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {
2063				error = EBUSY;
2064				pool_put(&pf_altq_pl, altq);
2065				break;
2066			}
2067			altq->altq_disc = NULL;
2068			TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
2069				if (strncmp(a->ifname, altq->ifname,
2070				    IFNAMSIZ) == 0 && a->qname[0] == '\0') {
2071					altq->altq_disc = a->altq_disc;
2072					break;
2073				}
2074			}
2075		}
2076
2077		error = altq_add(altq);
2078		if (error) {
2079			pool_put(&pf_altq_pl, altq);
2080			break;
2081		}
2082
2083		TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
2084		pf_altq_copyout(altq, &pa->altq);
2085		break;
2086	}
2087
2088	case DIOCGETALTQS: {
2089		struct pfioc_altq	*pa = (struct pfioc_altq *)(void *)addr;
2090		struct pf_altq		*altq;
2091		u_int32_t		nr;
2092
2093		VERIFY(altq_allowed);
2094		nr = 0;
2095		TAILQ_FOREACH(altq, pf_altqs_active, entries)
2096			nr++;
2097		bcopy(&nr, &pa->nr, sizeof (nr));
2098		bcopy(&ticket_altqs_active, &pa->ticket, sizeof (pa->ticket));
2099		break;
2100	}
2101
2102	case DIOCGETALTQ: {
2103		struct pfioc_altq	*pa = (struct pfioc_altq *)(void *)addr;
2104		struct pf_altq		*altq;
2105		u_int32_t		 nr, pa_nr, ticket;
2106
2107		VERIFY(altq_allowed);
2108		bcopy(&pa->ticket, &ticket, sizeof (ticket));
2109		if (ticket != ticket_altqs_active) {
2110			error = EBUSY;
2111			break;
2112		}
2113		bcopy(&pa->nr, &pa_nr, sizeof (pa_nr));
2114		nr = 0;
2115		altq = TAILQ_FIRST(pf_altqs_active);
2116		while ((altq != NULL) && (nr < pa_nr)) {
2117			altq = TAILQ_NEXT(altq, entries);
2118			nr++;
2119		}
2120		if (altq == NULL) {
2121			error = EBUSY;
2122			break;
2123		}
2124		pf_altq_copyout(altq, &pa->altq);
2125		break;
2126	}
2127
2128	case DIOCCHANGEALTQ:
2129		VERIFY(altq_allowed);
2130		/* CHANGEALTQ not supported yet! */
2131		error = ENODEV;
2132		break;
2133
2134	case DIOCGETQSTATS: {
2135		struct pfioc_qstats *pq = (struct pfioc_qstats *)(void *)addr;
2136		struct pf_altq		*altq;
2137		u_int32_t		 nr, pq_nr, ticket;
2138		int			 nbytes;
2139
2140		VERIFY(altq_allowed);
2141		bcopy(&pq->ticket, &ticket, sizeof (ticket));
2142		if (ticket != ticket_altqs_active) {
2143			error = EBUSY;
2144			break;
2145		}
2146		bcopy(&pq->nr, &pq_nr, sizeof (pq_nr));
2147		nr = 0;
2148		altq = TAILQ_FIRST(pf_altqs_active);
2149		while ((altq != NULL) && (nr < pq_nr)) {
2150			altq = TAILQ_NEXT(altq, entries);
2151			nr++;
2152		}
2153		if (altq == NULL) {
2154			error = EBUSY;
2155			break;
2156		}
2157		bcopy(&pq->nbytes, &nbytes, sizeof (nbytes));
2158		error = altq_getqstats(altq, pq->buf, &nbytes);
2159		if (error == 0) {
2160			pq->scheduler = altq->scheduler;
2161			bcopy(&nbytes, &pq->nbytes, sizeof (nbytes));
2162		}
2163		break;
2164	}
2165#endif /* PF_ALTQ */
2166
2167	case DIOCBEGINADDRS:		/* struct pfioc_pooladdr */
2168	case DIOCADDADDR:		/* struct pfioc_pooladdr */
2169	case DIOCGETADDRS:		/* struct pfioc_pooladdr */
2170	case DIOCGETADDR:		/* struct pfioc_pooladdr */
2171	case DIOCCHANGEADDR: {		/* struct pfioc_pooladdr */
2172		struct pfioc_pooladdr *pp = NULL;
2173
2174		PFIOC_STRUCT_BEGIN(addr, pp, error = ENOMEM; break;)
2175		error = pfioctl_ioc_pooladdr(cmd, pp, p);
2176		PFIOC_STRUCT_END(pp, addr);
2177		break;
2178	}
2179
2180	case DIOCGETRULESETS:		/* struct pfioc_ruleset */
2181	case DIOCGETRULESET: {		/* struct pfioc_ruleset */
2182		struct pfioc_ruleset *pr = NULL;
2183
2184		PFIOC_STRUCT_BEGIN(addr, pr, error = ENOMEM; break;);
2185		error = pfioctl_ioc_ruleset(cmd, pr, p);
2186		PFIOC_STRUCT_END(pr, addr);
2187		break;
2188	}
2189
2190	case DIOCRCLRTABLES:		/* struct pfioc_table */
2191	case DIOCRADDTABLES:		/* struct pfioc_table */
2192	case DIOCRDELTABLES:		/* struct pfioc_table */
2193	case DIOCRGETTABLES:		/* struct pfioc_table */
2194	case DIOCRGETTSTATS:		/* struct pfioc_table */
2195	case DIOCRCLRTSTATS:		/* struct pfioc_table */
2196	case DIOCRSETTFLAGS:		/* struct pfioc_table */
2197	case DIOCRCLRADDRS:		/* struct pfioc_table */
2198	case DIOCRADDADDRS:		/* struct pfioc_table */
2199	case DIOCRDELADDRS:		/* struct pfioc_table */
2200	case DIOCRSETADDRS:		/* struct pfioc_table */
2201	case DIOCRGETADDRS:		/* struct pfioc_table */
2202	case DIOCRGETASTATS:		/* struct pfioc_table */
2203	case DIOCRCLRASTATS:		/* struct pfioc_table */
2204	case DIOCRTSTADDRS:		/* struct pfioc_table */
2205	case DIOCRINADEFINE: {		/* struct pfioc_table */
2206		PFIOCX_STRUCT_DECL(pfioc_table);
2207
2208		PFIOCX_STRUCT_BEGIN(addr, pfioc_table, error = ENOMEM; break;);
2209		error = pfioctl_ioc_table(cmd,
2210		    PFIOCX_STRUCT_ADDR32(pfioc_table),
2211		    PFIOCX_STRUCT_ADDR64(pfioc_table), p);
2212		PFIOCX_STRUCT_END(pfioc_table, addr);
2213		break;
2214	}
2215
2216	case DIOCOSFPADD:		/* struct pf_osfp_ioctl */
2217	case DIOCOSFPGET: {		/* struct pf_osfp_ioctl */
2218		struct pf_osfp_ioctl *io = NULL;
2219
2220		PFIOC_STRUCT_BEGIN(addr, io, error = ENOMEM; break;);
2221		if (cmd == DIOCOSFPADD) {
2222			error = pf_osfp_add(io);
2223		} else {
2224			VERIFY(cmd == DIOCOSFPGET);
2225			error = pf_osfp_get(io);
2226		}
2227		PFIOC_STRUCT_END(io, addr);
2228		break;
2229	}
2230
2231	case DIOCXBEGIN:		/* struct pfioc_trans */
2232	case DIOCXROLLBACK:		/* struct pfioc_trans */
2233	case DIOCXCOMMIT: {		/* struct pfioc_trans */
2234		PFIOCX_STRUCT_DECL(pfioc_trans);
2235
2236		PFIOCX_STRUCT_BEGIN(addr, pfioc_trans, error = ENOMEM; break;);
2237		error = pfioctl_ioc_trans(cmd,
2238		    PFIOCX_STRUCT_ADDR32(pfioc_trans),
2239		    PFIOCX_STRUCT_ADDR64(pfioc_trans), p);
2240		PFIOCX_STRUCT_END(pfioc_trans, addr);
2241		break;
2242	}
2243
2244	case DIOCGETSRCNODES: {		/* struct pfioc_src_nodes */
2245		PFIOCX_STRUCT_DECL(pfioc_src_nodes);
2246
2247		PFIOCX_STRUCT_BEGIN(addr, pfioc_src_nodes,
2248		    error = ENOMEM; break;);
2249		error = pfioctl_ioc_src_nodes(cmd,
2250		    PFIOCX_STRUCT_ADDR32(pfioc_src_nodes),
2251		    PFIOCX_STRUCT_ADDR64(pfioc_src_nodes), p);
2252		PFIOCX_STRUCT_END(pfioc_src_nodes, addr);
2253		break;
2254	}
2255
2256	case DIOCCLRSRCNODES: {
2257		struct pf_src_node	*n;
2258		struct pf_state		*state;
2259
2260		RB_FOREACH(state, pf_state_tree_id, &tree_id) {
2261			state->src_node = NULL;
2262			state->nat_src_node = NULL;
2263		}
2264		RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
2265			n->expire = 1;
2266			n->states = 0;
2267		}
2268		pf_purge_expired_src_nodes();
2269		pf_status.src_nodes = 0;
2270		break;
2271	}
2272
2273	case DIOCKILLSRCNODES: {	/* struct pfioc_src_node_kill */
2274		struct pfioc_src_node_kill *psnk = NULL;
2275
2276		PFIOC_STRUCT_BEGIN(addr, psnk, error = ENOMEM; break;);
2277		error = pfioctl_ioc_src_node_kill(cmd, psnk, p);
2278		PFIOC_STRUCT_END(psnk, addr);
2279		break;
2280	}
2281
2282	case DIOCSETHOSTID: {		/* u_int32_t */
2283		u_int32_t hid;
2284
2285		/* small enough to be on stack */
2286		bcopy(addr, &hid, sizeof (hid));
2287		if (hid == 0)
2288			pf_status.hostid = random();
2289		else
2290			pf_status.hostid = hid;
2291		break;
2292	}
2293
2294	case DIOCOSFPFLUSH:
2295		pf_osfp_flush();
2296		break;
2297
2298	case DIOCIGETIFACES:		/* struct pfioc_iface */
2299	case DIOCSETIFFLAG:		/* struct pfioc_iface */
2300	case DIOCCLRIFFLAG: {		/* struct pfioc_iface */
2301		PFIOCX_STRUCT_DECL(pfioc_iface);
2302
2303		PFIOCX_STRUCT_BEGIN(addr, pfioc_iface, error = ENOMEM; break;);
2304		error = pfioctl_ioc_iface(cmd,
2305		    PFIOCX_STRUCT_ADDR32(pfioc_iface),
2306		    PFIOCX_STRUCT_ADDR64(pfioc_iface), p);
2307		PFIOCX_STRUCT_END(pfioc_iface, addr);
2308		break;
2309	}
2310
2311	default:
2312		error = ENODEV;
2313		break;
2314	}
2315
2316	lck_mtx_unlock(pf_lock);
2317	lck_rw_done(pf_perim_lock);
2318
2319	return (error);
2320}
2321
2322static int
2323pfioctl_ioc_table(u_long cmd, struct pfioc_table_32 *io32,
2324    struct pfioc_table_64 *io64, struct proc *p)
2325{
2326	int p64 = proc_is64bit(p);
2327	int error = 0;
2328
2329	if (!p64)
2330		goto struct32;
2331
2332	/*
2333	 * 64-bit structure processing
2334	 */
2335	switch (cmd) {
2336	case DIOCRCLRTABLES:
2337		if (io64->pfrio_esize != 0) {
2338			error = ENODEV;
2339			break;
2340		}
2341		pfr_table_copyin_cleanup(&io64->pfrio_table);
2342		error = pfr_clr_tables(&io64->pfrio_table, &io64->pfrio_ndel,
2343		    io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2344		break;
2345
2346	case DIOCRADDTABLES:
2347		if (io64->pfrio_esize != sizeof (struct pfr_table)) {
2348			error = ENODEV;
2349			break;
2350		}
2351		error = pfr_add_tables(io64->pfrio_buffer, io64->pfrio_size,
2352		    &io64->pfrio_nadd, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2353		break;
2354
2355	case DIOCRDELTABLES:
2356		if (io64->pfrio_esize != sizeof (struct pfr_table)) {
2357			error = ENODEV;
2358			break;
2359		}
2360		error = pfr_del_tables(io64->pfrio_buffer, io64->pfrio_size,
2361		    &io64->pfrio_ndel, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2362		break;
2363
2364	case DIOCRGETTABLES:
2365		if (io64->pfrio_esize != sizeof (struct pfr_table)) {
2366			error = ENODEV;
2367			break;
2368		}
2369		pfr_table_copyin_cleanup(&io64->pfrio_table);
2370		error = pfr_get_tables(&io64->pfrio_table, io64->pfrio_buffer,
2371		    &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2372		break;
2373
2374	case DIOCRGETTSTATS:
2375		if (io64->pfrio_esize != sizeof (struct pfr_tstats)) {
2376			error = ENODEV;
2377			break;
2378		}
2379		pfr_table_copyin_cleanup(&io64->pfrio_table);
2380		error = pfr_get_tstats(&io64->pfrio_table, io64->pfrio_buffer,
2381		    &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2382		break;
2383
2384	case DIOCRCLRTSTATS:
2385		if (io64->pfrio_esize != sizeof (struct pfr_table)) {
2386			error = ENODEV;
2387			break;
2388		}
2389		error = pfr_clr_tstats(io64->pfrio_buffer, io64->pfrio_size,
2390		    &io64->pfrio_nzero, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2391		break;
2392
2393	case DIOCRSETTFLAGS:
2394		if (io64->pfrio_esize != sizeof (struct pfr_table)) {
2395			error = ENODEV;
2396			break;
2397		}
2398		error = pfr_set_tflags(io64->pfrio_buffer, io64->pfrio_size,
2399		    io64->pfrio_setflag, io64->pfrio_clrflag,
2400		    &io64->pfrio_nchange, &io64->pfrio_ndel,
2401		    io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2402		break;
2403
2404	case DIOCRCLRADDRS:
2405		if (io64->pfrio_esize != 0) {
2406			error = ENODEV;
2407			break;
2408		}
2409		pfr_table_copyin_cleanup(&io64->pfrio_table);
2410		error = pfr_clr_addrs(&io64->pfrio_table, &io64->pfrio_ndel,
2411		    io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2412		break;
2413
2414	case DIOCRADDADDRS:
2415		if (io64->pfrio_esize != sizeof (struct pfr_addr)) {
2416			error = ENODEV;
2417			break;
2418		}
2419		pfr_table_copyin_cleanup(&io64->pfrio_table);
2420		error = pfr_add_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2421		    io64->pfrio_size, &io64->pfrio_nadd, io64->pfrio_flags |
2422		    PFR_FLAG_USERIOCTL);
2423		break;
2424
2425	case DIOCRDELADDRS:
2426		if (io64->pfrio_esize != sizeof (struct pfr_addr)) {
2427			error = ENODEV;
2428			break;
2429		}
2430		pfr_table_copyin_cleanup(&io64->pfrio_table);
2431		error = pfr_del_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2432		    io64->pfrio_size, &io64->pfrio_ndel, io64->pfrio_flags |
2433		    PFR_FLAG_USERIOCTL);
2434		break;
2435
2436	case DIOCRSETADDRS:
2437		if (io64->pfrio_esize != sizeof (struct pfr_addr)) {
2438			error = ENODEV;
2439			break;
2440		}
2441		pfr_table_copyin_cleanup(&io64->pfrio_table);
2442		error = pfr_set_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2443		    io64->pfrio_size, &io64->pfrio_size2, &io64->pfrio_nadd,
2444		    &io64->pfrio_ndel, &io64->pfrio_nchange, io64->pfrio_flags |
2445		    PFR_FLAG_USERIOCTL, 0);
2446		break;
2447
2448	case DIOCRGETADDRS:
2449		if (io64->pfrio_esize != sizeof (struct pfr_addr)) {
2450			error = ENODEV;
2451			break;
2452		}
2453		pfr_table_copyin_cleanup(&io64->pfrio_table);
2454		error = pfr_get_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2455		    &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2456		break;
2457
2458	case DIOCRGETASTATS:
2459		if (io64->pfrio_esize != sizeof (struct pfr_astats)) {
2460			error = ENODEV;
2461			break;
2462		}
2463		pfr_table_copyin_cleanup(&io64->pfrio_table);
2464		error = pfr_get_astats(&io64->pfrio_table, io64->pfrio_buffer,
2465		    &io64->pfrio_size, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2466		break;
2467
2468	case DIOCRCLRASTATS:
2469		if (io64->pfrio_esize != sizeof (struct pfr_addr)) {
2470			error = ENODEV;
2471			break;
2472		}
2473		pfr_table_copyin_cleanup(&io64->pfrio_table);
2474		error = pfr_clr_astats(&io64->pfrio_table, io64->pfrio_buffer,
2475		    io64->pfrio_size, &io64->pfrio_nzero, io64->pfrio_flags |
2476		    PFR_FLAG_USERIOCTL);
2477		break;
2478
2479	case DIOCRTSTADDRS:
2480		if (io64->pfrio_esize != sizeof (struct pfr_addr)) {
2481			error = ENODEV;
2482			break;
2483		}
2484		pfr_table_copyin_cleanup(&io64->pfrio_table);
2485		error = pfr_tst_addrs(&io64->pfrio_table, io64->pfrio_buffer,
2486		    io64->pfrio_size, &io64->pfrio_nmatch, io64->pfrio_flags |
2487		    PFR_FLAG_USERIOCTL);
2488		break;
2489
2490	case DIOCRINADEFINE:
2491		if (io64->pfrio_esize != sizeof (struct pfr_addr)) {
2492			error = ENODEV;
2493			break;
2494		}
2495		pfr_table_copyin_cleanup(&io64->pfrio_table);
2496		error = pfr_ina_define(&io64->pfrio_table, io64->pfrio_buffer,
2497		    io64->pfrio_size, &io64->pfrio_nadd, &io64->pfrio_naddr,
2498		    io64->pfrio_ticket, io64->pfrio_flags | PFR_FLAG_USERIOCTL);
2499		break;
2500
2501	default:
2502		VERIFY(0);
2503		/* NOTREACHED */
2504	}
2505	goto done;
2506
2507struct32:
2508	/*
2509	 * 32-bit structure processing
2510	 */
2511	switch (cmd) {
2512	case DIOCRCLRTABLES:
2513		if (io32->pfrio_esize != 0) {
2514			error = ENODEV;
2515			break;
2516		}
2517		pfr_table_copyin_cleanup(&io32->pfrio_table);
2518		error = pfr_clr_tables(&io32->pfrio_table, &io32->pfrio_ndel,
2519		    io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2520		break;
2521
2522	case DIOCRADDTABLES:
2523		if (io32->pfrio_esize != sizeof (struct pfr_table)) {
2524			error = ENODEV;
2525			break;
2526		}
2527		error = pfr_add_tables(io32->pfrio_buffer, io32->pfrio_size,
2528		    &io32->pfrio_nadd, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2529		break;
2530
2531	case DIOCRDELTABLES:
2532		if (io32->pfrio_esize != sizeof (struct pfr_table)) {
2533			error = ENODEV;
2534			break;
2535		}
2536		error = pfr_del_tables(io32->pfrio_buffer, io32->pfrio_size,
2537		    &io32->pfrio_ndel, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2538		break;
2539
2540	case DIOCRGETTABLES:
2541		if (io32->pfrio_esize != sizeof (struct pfr_table)) {
2542			error = ENODEV;
2543			break;
2544		}
2545		pfr_table_copyin_cleanup(&io32->pfrio_table);
2546		error = pfr_get_tables(&io32->pfrio_table, io32->pfrio_buffer,
2547		    &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2548		break;
2549
2550	case DIOCRGETTSTATS:
2551		if (io32->pfrio_esize != sizeof (struct pfr_tstats)) {
2552			error = ENODEV;
2553			break;
2554		}
2555		pfr_table_copyin_cleanup(&io32->pfrio_table);
2556		error = pfr_get_tstats(&io32->pfrio_table, io32->pfrio_buffer,
2557		    &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2558		break;
2559
2560	case DIOCRCLRTSTATS:
2561		if (io32->pfrio_esize != sizeof (struct pfr_table)) {
2562			error = ENODEV;
2563			break;
2564		}
2565		error = pfr_clr_tstats(io32->pfrio_buffer, io32->pfrio_size,
2566		    &io32->pfrio_nzero, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2567		break;
2568
2569	case DIOCRSETTFLAGS:
2570		if (io32->pfrio_esize != sizeof (struct pfr_table)) {
2571			error = ENODEV;
2572			break;
2573		}
2574		error = pfr_set_tflags(io32->pfrio_buffer, io32->pfrio_size,
2575		    io32->pfrio_setflag, io32->pfrio_clrflag,
2576		    &io32->pfrio_nchange, &io32->pfrio_ndel,
2577		    io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2578		break;
2579
2580	case DIOCRCLRADDRS:
2581		if (io32->pfrio_esize != 0) {
2582			error = ENODEV;
2583			break;
2584		}
2585		pfr_table_copyin_cleanup(&io32->pfrio_table);
2586		error = pfr_clr_addrs(&io32->pfrio_table, &io32->pfrio_ndel,
2587		    io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2588		break;
2589
2590	case DIOCRADDADDRS:
2591		if (io32->pfrio_esize != sizeof (struct pfr_addr)) {
2592			error = ENODEV;
2593			break;
2594		}
2595		pfr_table_copyin_cleanup(&io32->pfrio_table);
2596		error = pfr_add_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2597		    io32->pfrio_size, &io32->pfrio_nadd, io32->pfrio_flags |
2598		    PFR_FLAG_USERIOCTL);
2599		break;
2600
2601	case DIOCRDELADDRS:
2602		if (io32->pfrio_esize != sizeof (struct pfr_addr)) {
2603			error = ENODEV;
2604			break;
2605		}
2606		pfr_table_copyin_cleanup(&io32->pfrio_table);
2607		error = pfr_del_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2608		    io32->pfrio_size, &io32->pfrio_ndel, io32->pfrio_flags |
2609		    PFR_FLAG_USERIOCTL);
2610		break;
2611
2612	case DIOCRSETADDRS:
2613		if (io32->pfrio_esize != sizeof (struct pfr_addr)) {
2614			error = ENODEV;
2615			break;
2616		}
2617		pfr_table_copyin_cleanup(&io32->pfrio_table);
2618		error = pfr_set_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2619		    io32->pfrio_size, &io32->pfrio_size2, &io32->pfrio_nadd,
2620		    &io32->pfrio_ndel, &io32->pfrio_nchange, io32->pfrio_flags |
2621		    PFR_FLAG_USERIOCTL, 0);
2622		break;
2623
2624	case DIOCRGETADDRS:
2625		if (io32->pfrio_esize != sizeof (struct pfr_addr)) {
2626			error = ENODEV;
2627			break;
2628		}
2629		pfr_table_copyin_cleanup(&io32->pfrio_table);
2630		error = pfr_get_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2631		    &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2632		break;
2633
2634	case DIOCRGETASTATS:
2635		if (io32->pfrio_esize != sizeof (struct pfr_astats)) {
2636			error = ENODEV;
2637			break;
2638		}
2639		pfr_table_copyin_cleanup(&io32->pfrio_table);
2640		error = pfr_get_astats(&io32->pfrio_table, io32->pfrio_buffer,
2641		    &io32->pfrio_size, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2642		break;
2643
2644	case DIOCRCLRASTATS:
2645		if (io32->pfrio_esize != sizeof (struct pfr_addr)) {
2646			error = ENODEV;
2647			break;
2648		}
2649		pfr_table_copyin_cleanup(&io32->pfrio_table);
2650		error = pfr_clr_astats(&io32->pfrio_table, io32->pfrio_buffer,
2651		    io32->pfrio_size, &io32->pfrio_nzero, io32->pfrio_flags |
2652		    PFR_FLAG_USERIOCTL);
2653		break;
2654
2655	case DIOCRTSTADDRS:
2656		if (io32->pfrio_esize != sizeof (struct pfr_addr)) {
2657			error = ENODEV;
2658			break;
2659		}
2660		pfr_table_copyin_cleanup(&io32->pfrio_table);
2661		error = pfr_tst_addrs(&io32->pfrio_table, io32->pfrio_buffer,
2662		    io32->pfrio_size, &io32->pfrio_nmatch, io32->pfrio_flags |
2663		    PFR_FLAG_USERIOCTL);
2664		break;
2665
2666	case DIOCRINADEFINE:
2667		if (io32->pfrio_esize != sizeof (struct pfr_addr)) {
2668			error = ENODEV;
2669			break;
2670		}
2671		pfr_table_copyin_cleanup(&io32->pfrio_table);
2672		error = pfr_ina_define(&io32->pfrio_table, io32->pfrio_buffer,
2673		    io32->pfrio_size, &io32->pfrio_nadd, &io32->pfrio_naddr,
2674		    io32->pfrio_ticket, io32->pfrio_flags | PFR_FLAG_USERIOCTL);
2675		break;
2676
2677	default:
2678		VERIFY(0);
2679		/* NOTREACHED */
2680	}
2681
2682done:
2683	return (error);
2684}
2685
2686static int
2687pfioctl_ioc_tokens(u_long cmd, struct pfioc_tokens_32 *tok32,
2688    struct pfioc_tokens_64 *tok64, struct proc *p)
2689{
2690	struct pfioc_token *tokens;
2691	struct pfioc_kernel_token *entry, *tmp;
2692	user_addr_t token_buf;
2693	int ocnt, cnt, error = 0, p64 = proc_is64bit(p);
2694	char *ptr;
2695
2696	switch (cmd) {
2697	case DIOCGETSTARTERS: {
2698		int size;
2699
2700		if (nr_tokens == 0) {
2701			error = ENOENT;
2702			break;
2703		}
2704
2705		size = sizeof (struct pfioc_token) * nr_tokens;
2706		ocnt = cnt = (p64 ? tok64->size : tok32->size);
2707		if (cnt == 0) {
2708			if (p64)
2709				tok64->size = size;
2710			else
2711				tok32->size = size;
2712			break;
2713		}
2714
2715		token_buf = (p64 ? tok64->pgt_buf : tok32->pgt_buf);
2716		tokens = _MALLOC(size, M_TEMP, M_WAITOK|M_ZERO);
2717		if (tokens == NULL) {
2718			error = ENOMEM;
2719			break;
2720		}
2721
2722		ptr = (void *)tokens;
2723		SLIST_FOREACH_SAFE(entry, &token_list_head, next, tmp) {
2724			struct pfioc_token *t;
2725
2726			if ((unsigned)cnt < sizeof (*tokens))
2727				break;    /* no more buffer space left */
2728
2729			t = (struct pfioc_token *)(void *)ptr;
2730			t->token_value	= entry->token.token_value;
2731			t->timestamp	= entry->token.timestamp;
2732			t->pid		= entry->token.pid;
2733			bcopy(entry->token.proc_name, t->proc_name,
2734			    PFTOK_PROCNAME_LEN);
2735			ptr += sizeof (struct pfioc_token);
2736
2737			cnt -= sizeof (struct pfioc_token);
2738		}
2739
2740		if (cnt < ocnt)
2741			error = copyout(tokens, token_buf, ocnt - cnt);
2742
2743		if (p64)
2744			tok64->size = ocnt - cnt;
2745		else
2746			tok32->size = ocnt - cnt;
2747
2748		_FREE(tokens, M_TEMP);
2749		break;
2750	}
2751
2752	default:
2753		VERIFY(0);
2754		/* NOTREACHED */
2755	}
2756
2757	return (error);
2758}
2759
2760static void
2761pf_expire_states_and_src_nodes(struct pf_rule *rule)
2762{
2763	struct pf_state		*state;
2764	struct pf_src_node	*sn;
2765	int			 killed = 0;
2766
2767	/* expire the states */
2768	state = TAILQ_FIRST(&state_list);
2769	while (state) {
2770		if (state->rule.ptr == rule)
2771			state->timeout = PFTM_PURGE;
2772		state = TAILQ_NEXT(state, entry_list);
2773	}
2774	pf_purge_expired_states(pf_status.states);
2775
2776	/* expire the src_nodes */
2777	RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
2778		if (sn->rule.ptr != rule)
2779			continue;
2780		if (sn->states != 0) {
2781			RB_FOREACH(state, pf_state_tree_id,
2782			    &tree_id) {
2783				if (state->src_node == sn)
2784					state->src_node = NULL;
2785				if (state->nat_src_node == sn)
2786					state->nat_src_node = NULL;
2787			}
2788			sn->states = 0;
2789		}
2790		sn->expire = 1;
2791		killed++;
2792	}
2793	if (killed)
2794		pf_purge_expired_src_nodes();
2795}
2796
2797static void
2798pf_delete_rule_from_ruleset(struct pf_ruleset *ruleset, int rs_num,
2799    struct pf_rule *rule)
2800{
2801	struct pf_rule *r;
2802	int nr = 0;
2803
2804	pf_expire_states_and_src_nodes(rule);
2805
2806	pf_rm_rule(ruleset->rules[rs_num].active.ptr, rule);
2807	if (ruleset->rules[rs_num].active.rcount-- == 0)
2808		panic("%s: rcount value broken!", __func__);
2809	r = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
2810
2811	while (r) {
2812		r->nr = nr++;
2813		r = TAILQ_NEXT(r, entries);
2814	}
2815}
2816
2817
2818static void
2819pf_ruleset_cleanup(struct pf_ruleset *ruleset, int rs)
2820{
2821	pf_calc_skip_steps(ruleset->rules[rs].active.ptr);
2822	ruleset->rules[rs].active.ticket =
2823	    ++ruleset->rules[rs].inactive.ticket;
2824}
2825
2826/*
2827 * req_dev encodes the PF interface. Currently, possible values are
2828 * 0 or PFRULE_PFM
2829 */
2830static int
2831pf_delete_rule_by_ticket(struct pfioc_rule *pr, u_int32_t req_dev)
2832{
2833	struct pf_ruleset	*ruleset;
2834	struct pf_rule		*rule = NULL;
2835	int			 is_anchor;
2836	int			 error;
2837	int			 i;
2838
2839	is_anchor = (pr->anchor_call[0] != '\0');
2840	if ((ruleset = pf_find_ruleset_with_owner(pr->anchor,
2841	    pr->rule.owner, is_anchor, &error)) == NULL)
2842		return (error);
2843
2844	for (i = 0; i < PF_RULESET_MAX && rule == NULL; i++) {
2845		rule = TAILQ_FIRST(ruleset->rules[i].active.ptr);
2846		while (rule && (rule->ticket != pr->rule.ticket))
2847			rule = TAILQ_NEXT(rule, entries);
2848	}
2849	if (rule == NULL)
2850		return (ENOENT);
2851	else
2852		i--;
2853
2854	if (strcmp(rule->owner, pr->rule.owner))
2855		return (EACCES);
2856
2857delete_rule:
2858	if (rule->anchor && (ruleset != &pf_main_ruleset) &&
2859	    ((strcmp(ruleset->anchor->owner, "")) == 0) &&
2860	    ((ruleset->rules[i].active.rcount - 1) == 0)) {
2861		/* set rule & ruleset to parent and repeat */
2862		struct pf_rule *delete_rule = rule;
2863		struct pf_ruleset *delete_ruleset = ruleset;
2864
2865#define	parent_ruleset		ruleset->anchor->parent->ruleset
2866		if (ruleset->anchor->parent == NULL)
2867			ruleset = &pf_main_ruleset;
2868		else
2869			ruleset = &parent_ruleset;
2870
2871		rule = TAILQ_FIRST(ruleset->rules[i].active.ptr);
2872		while (rule &&
2873		    (rule->anchor != delete_ruleset->anchor))
2874			rule = TAILQ_NEXT(rule, entries);
2875		if (rule == NULL)
2876			panic("%s: rule not found!", __func__);
2877
2878		/*
2879		 * if reqest device != rule's device, bail :
2880		 * with error if ticket matches;
2881		 * without error if ticket doesn't match (i.e. its just cleanup)
2882		 */
2883		if ((rule->rule_flag & PFRULE_PFM) ^ req_dev) {
2884			if (rule->ticket != pr->rule.ticket) {
2885				return (0);
2886			} else {
2887				return EACCES;
2888			}
2889		}
2890
2891		if (delete_rule->rule_flag & PFRULE_PFM) {
2892			pffwrules--;
2893		}
2894
2895		pf_delete_rule_from_ruleset(delete_ruleset,
2896		    i, delete_rule);
2897		delete_ruleset->rules[i].active.ticket =
2898		    ++delete_ruleset->rules[i].inactive.ticket;
2899		goto delete_rule;
2900	} else {
2901		/*
2902		 * process deleting rule only if device that added the
2903		 * rule matches device that issued the request
2904		 */
2905		if ((rule->rule_flag & PFRULE_PFM) ^ req_dev)
2906			return EACCES;
2907		if (rule->rule_flag & PFRULE_PFM)
2908			pffwrules--;
2909		pf_delete_rule_from_ruleset(ruleset, i,
2910		    rule);
2911		pf_ruleset_cleanup(ruleset, i);
2912	}
2913
2914	return (0);
2915}
2916
2917/*
2918 * req_dev encodes the PF interface. Currently, possible values are
2919 * 0 or PFRULE_PFM
2920 */
2921static void
2922pf_delete_rule_by_owner(char *owner, u_int32_t req_dev)
2923{
2924	struct pf_ruleset	*ruleset;
2925	struct pf_rule		*rule, *next;
2926	int			 deleted = 0;
2927
2928	for (int rs = 0; rs < PF_RULESET_MAX; rs++) {
2929		rule = TAILQ_FIRST(pf_main_ruleset.rules[rs].active.ptr);
2930		ruleset = &pf_main_ruleset;
2931		while (rule) {
2932			next = TAILQ_NEXT(rule, entries);
2933			/*
2934			 * process deleting rule only if device that added the
2935			 * rule matches device that issued the request
2936			 */
2937			if ((rule->rule_flag & PFRULE_PFM) ^ req_dev) {
2938				rule = next;
2939				continue;
2940			}
2941			if (rule->anchor) {
2942				if (((strcmp(rule->owner, owner)) == 0) ||
2943				    ((strcmp(rule->owner, "")) == 0)) {
2944					if (rule->anchor->ruleset.rules[rs].active.rcount > 0) {
2945						if (deleted) {
2946							pf_ruleset_cleanup(ruleset, rs);
2947							deleted = 0;
2948						}
2949						/* step into anchor */
2950						ruleset =
2951						    &rule->anchor->ruleset;
2952						rule = TAILQ_FIRST(ruleset->rules[rs].active.ptr);
2953						continue;
2954					} else {
2955						if (rule->rule_flag &
2956						    PFRULE_PFM)
2957							pffwrules--;
2958						pf_delete_rule_from_ruleset(ruleset, rs, rule);
2959						deleted = 1;
2960						rule = next;
2961					}
2962				} else
2963					rule = next;
2964			} else {
2965				if (((strcmp(rule->owner, owner)) == 0)) {
2966					/* delete rule */
2967					if (rule->rule_flag & PFRULE_PFM)
2968						pffwrules--;
2969					pf_delete_rule_from_ruleset(ruleset,
2970					    rs, rule);
2971					deleted = 1;
2972				}
2973				rule = next;
2974			}
2975			if (rule == NULL) {
2976				if (deleted) {
2977					pf_ruleset_cleanup(ruleset, rs);
2978					deleted = 0;
2979				}
2980				if (ruleset != &pf_main_ruleset)
2981					pf_deleterule_anchor_step_out(&ruleset,
2982					    rs, &rule);
2983			}
2984		}
2985	}
2986}
2987
2988static void
2989pf_deleterule_anchor_step_out(struct pf_ruleset **ruleset_ptr,
2990    int rs, struct pf_rule **rule_ptr)
2991{
2992	struct pf_ruleset *ruleset = *ruleset_ptr;
2993	struct pf_rule *rule = *rule_ptr;
2994
2995	/* step out of anchor */
2996	struct pf_ruleset *rs_copy = ruleset;
2997	ruleset = ruleset->anchor->parent?
2998	    &ruleset->anchor->parent->ruleset:&pf_main_ruleset;
2999
3000	rule = TAILQ_FIRST(ruleset->rules[rs].active.ptr);
3001	while (rule && (rule->anchor != rs_copy->anchor))
3002		rule = TAILQ_NEXT(rule, entries);
3003	if (rule == NULL)
3004		panic("%s: parent rule of anchor not found!", __func__);
3005	if (rule->anchor->ruleset.rules[rs].active.rcount > 0)
3006		rule = TAILQ_NEXT(rule, entries);
3007
3008	*ruleset_ptr = ruleset;
3009	*rule_ptr = rule;
3010}
3011
3012static void
3013pf_addrwrap_setup(struct pf_addr_wrap *aw)
3014{
3015	VERIFY(aw);
3016	bzero(&aw->p, sizeof aw->p);
3017}
3018
3019static int
3020pf_rule_setup(struct pfioc_rule *pr, struct pf_rule *rule,
3021    struct pf_ruleset *ruleset) {
3022	struct pf_pooladdr 	*apa;
3023	int			 error = 0;
3024
3025	if (rule->ifname[0]) {
3026		rule->kif = pfi_kif_get(rule->ifname);
3027		if (rule->kif == NULL) {
3028			pool_put(&pf_rule_pl, rule);
3029			return (EINVAL);
3030		}
3031		pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
3032	}
3033#if PF_ALTQ
3034	/* set queue IDs */
3035	if (altq_allowed && rule->qname[0] != '\0') {
3036		if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
3037			error = EBUSY;
3038		else if (rule->pqname[0] != '\0') {
3039			if ((rule->pqid =
3040			    pf_qname2qid(rule->pqname)) == 0)
3041				error = EBUSY;
3042		} else
3043			rule->pqid = rule->qid;
3044	}
3045#endif /* PF_ALTQ */
3046	if (rule->tagname[0])
3047		if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
3048			error = EBUSY;
3049	if (rule->match_tagname[0])
3050		if ((rule->match_tag =
3051		    pf_tagname2tag(rule->match_tagname)) == 0)
3052			error = EBUSY;
3053	if (rule->rt && !rule->direction)
3054		error = EINVAL;
3055#if PFLOG
3056	if (!rule->log)
3057		rule->logif = 0;
3058	if (rule->logif >= PFLOGIFS_MAX)
3059		error = EINVAL;
3060#endif /* PFLOG */
3061	pf_addrwrap_setup(&rule->src.addr);
3062	pf_addrwrap_setup(&rule->dst.addr);
3063	if (pf_rtlabel_add(&rule->src.addr) ||
3064	    pf_rtlabel_add(&rule->dst.addr))
3065		error = EBUSY;
3066	if (pfi_dynaddr_setup(&rule->src.addr, rule->af))
3067		error = EINVAL;
3068	if (pfi_dynaddr_setup(&rule->dst.addr, rule->af))
3069		error = EINVAL;
3070	if (pf_tbladdr_setup(ruleset, &rule->src.addr))
3071		error = EINVAL;
3072	if (pf_tbladdr_setup(ruleset, &rule->dst.addr))
3073		error = EINVAL;
3074	if (pf_anchor_setup(rule, ruleset, pr->anchor_call))
3075		error = EINVAL;
3076	TAILQ_FOREACH(apa, &pf_pabuf, entries)
3077		if (pf_tbladdr_setup(ruleset, &apa->addr))
3078			error = EINVAL;
3079
3080	if (rule->overload_tblname[0]) {
3081		if ((rule->overload_tbl = pfr_attach_table(ruleset,
3082		    rule->overload_tblname)) == NULL)
3083			error = EINVAL;
3084		else
3085			rule->overload_tbl->pfrkt_flags |=
3086			    PFR_TFLAG_ACTIVE;
3087	}
3088
3089	pf_mv_pool(&pf_pabuf, &rule->rpool.list);
3090	if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
3091	    (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
3092	    (rule->rt > PF_FASTROUTE)) &&
3093	    (TAILQ_FIRST(&rule->rpool.list) == NULL))
3094		error = EINVAL;
3095
3096	if (error) {
3097		pf_rm_rule(NULL, rule);
3098		return (error);
3099	}
3100	rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
3101	rule->evaluations = rule->packets[0] = rule->packets[1] =
3102	    rule->bytes[0] = rule->bytes[1] = 0;
3103
3104	return (0);
3105}
3106
3107static int
3108pfioctl_ioc_rule(u_long cmd, int minordev, struct pfioc_rule *pr, struct proc *p)
3109{
3110	int error = 0;
3111	u_int32_t req_dev = 0;
3112
3113	switch (cmd) {
3114	case DIOCADDRULE: {
3115		struct pf_ruleset	*ruleset;
3116		struct pf_rule		*rule, *tail;
3117		int			rs_num;
3118
3119		pr->anchor[sizeof (pr->anchor) - 1] = '\0';
3120		pr->anchor_call[sizeof (pr->anchor_call) - 1] = '\0';
3121		ruleset = pf_find_ruleset(pr->anchor);
3122		if (ruleset == NULL) {
3123			error = EINVAL;
3124			break;
3125		}
3126		rs_num = pf_get_ruleset_number(pr->rule.action);
3127		if (rs_num >= PF_RULESET_MAX) {
3128			error = EINVAL;
3129			break;
3130		}
3131		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3132			error = EINVAL;
3133			break;
3134		}
3135		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
3136			error = EBUSY;
3137			break;
3138		}
3139		if (pr->pool_ticket != ticket_pabuf) {
3140			error = EBUSY;
3141			break;
3142		}
3143		rule = pool_get(&pf_rule_pl, PR_WAITOK);
3144		if (rule == NULL) {
3145			error = ENOMEM;
3146			break;
3147		}
3148		pf_rule_copyin(&pr->rule, rule, p, minordev);
3149#if !INET
3150		if (rule->af == AF_INET) {
3151			pool_put(&pf_rule_pl, rule);
3152			error = EAFNOSUPPORT;
3153			break;
3154		}
3155#endif /* INET */
3156#if !INET6
3157		if (rule->af == AF_INET6) {
3158			pool_put(&pf_rule_pl, rule);
3159			error = EAFNOSUPPORT;
3160			break;
3161		}
3162#endif /* INET6 */
3163		tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
3164		    pf_rulequeue);
3165		if (tail)
3166			rule->nr = tail->nr + 1;
3167		else
3168			rule->nr = 0;
3169
3170		if ((error = pf_rule_setup(pr, rule, ruleset)))
3171			break;
3172
3173		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
3174		    rule, entries);
3175		ruleset->rules[rs_num].inactive.rcount++;
3176		if (rule->rule_flag & PFRULE_PFM)
3177			pffwrules++;
3178		break;
3179	}
3180
3181	case DIOCGETRULES: {
3182		struct pf_ruleset	*ruleset;
3183		struct pf_rule		*tail;
3184		int			 rs_num;
3185
3186		pr->anchor[sizeof (pr->anchor) - 1] = '\0';
3187		pr->anchor_call[sizeof (pr->anchor_call) - 1] = '\0';
3188		ruleset = pf_find_ruleset(pr->anchor);
3189		if (ruleset == NULL) {
3190			error = EINVAL;
3191			break;
3192		}
3193		rs_num = pf_get_ruleset_number(pr->rule.action);
3194		if (rs_num >= PF_RULESET_MAX) {
3195			error = EINVAL;
3196			break;
3197		}
3198		tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
3199		    pf_rulequeue);
3200		if (tail)
3201			pr->nr = tail->nr + 1;
3202		else
3203			pr->nr = 0;
3204		pr->ticket = ruleset->rules[rs_num].active.ticket;
3205		break;
3206	}
3207
3208	case DIOCGETRULE: {
3209		struct pf_ruleset	*ruleset;
3210		struct pf_rule		*rule;
3211		int			 rs_num, i;
3212
3213		pr->anchor[sizeof (pr->anchor) - 1] = '\0';
3214		pr->anchor_call[sizeof (pr->anchor_call) - 1] = '\0';
3215		ruleset = pf_find_ruleset(pr->anchor);
3216		if (ruleset == NULL) {
3217			error = EINVAL;
3218			break;
3219		}
3220		rs_num = pf_get_ruleset_number(pr->rule.action);
3221		if (rs_num >= PF_RULESET_MAX) {
3222			error = EINVAL;
3223			break;
3224		}
3225		if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
3226			error = EBUSY;
3227			break;
3228		}
3229		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
3230		while ((rule != NULL) && (rule->nr != pr->nr))
3231			rule = TAILQ_NEXT(rule, entries);
3232		if (rule == NULL) {
3233			error = EBUSY;
3234			break;
3235		}
3236		pf_rule_copyout(rule, &pr->rule);
3237		if (pf_anchor_copyout(ruleset, rule, pr)) {
3238			error = EBUSY;
3239			break;
3240		}
3241		pfi_dynaddr_copyout(&pr->rule.src.addr);
3242		pfi_dynaddr_copyout(&pr->rule.dst.addr);
3243		pf_tbladdr_copyout(&pr->rule.src.addr);
3244		pf_tbladdr_copyout(&pr->rule.dst.addr);
3245		pf_rtlabel_copyout(&pr->rule.src.addr);
3246		pf_rtlabel_copyout(&pr->rule.dst.addr);
3247		for (i = 0; i < PF_SKIP_COUNT; ++i)
3248			if (rule->skip[i].ptr == NULL)
3249				pr->rule.skip[i].nr = -1;
3250			else
3251				pr->rule.skip[i].nr =
3252				    rule->skip[i].ptr->nr;
3253
3254		if (pr->action == PF_GET_CLR_CNTR) {
3255			rule->evaluations = 0;
3256			rule->packets[0] = rule->packets[1] = 0;
3257			rule->bytes[0] = rule->bytes[1] = 0;
3258		}
3259		break;
3260	}
3261
3262	case DIOCCHANGERULE: {
3263		struct pfioc_rule	*pcr = pr;
3264		struct pf_ruleset	*ruleset;
3265		struct pf_rule		*oldrule = NULL, *newrule = NULL;
3266		struct pf_pooladdr	*pa;
3267		u_int32_t		 nr = 0;
3268		int			 rs_num;
3269
3270		if (!(pcr->action == PF_CHANGE_REMOVE ||
3271		    pcr->action == PF_CHANGE_GET_TICKET) &&
3272		    pcr->pool_ticket != ticket_pabuf) {
3273			error = EBUSY;
3274			break;
3275		}
3276
3277		if (pcr->action < PF_CHANGE_ADD_HEAD ||
3278		    pcr->action > PF_CHANGE_GET_TICKET) {
3279			error = EINVAL;
3280			break;
3281		}
3282		pcr->anchor[sizeof (pcr->anchor) - 1] = '\0';
3283		pcr->anchor_call[sizeof (pcr->anchor_call) - 1] = '\0';
3284		ruleset = pf_find_ruleset(pcr->anchor);
3285		if (ruleset == NULL) {
3286			error = EINVAL;
3287			break;
3288		}
3289		rs_num = pf_get_ruleset_number(pcr->rule.action);
3290		if (rs_num >= PF_RULESET_MAX) {
3291			error = EINVAL;
3292			break;
3293		}
3294
3295		if (pcr->action == PF_CHANGE_GET_TICKET) {
3296			pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
3297			break;
3298		} else {
3299			if (pcr->ticket !=
3300			    ruleset->rules[rs_num].active.ticket) {
3301				error = EINVAL;
3302				break;
3303			}
3304			if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3305				error = EINVAL;
3306				break;
3307			}
3308		}
3309
3310		if (pcr->action != PF_CHANGE_REMOVE) {
3311			newrule = pool_get(&pf_rule_pl, PR_WAITOK);
3312			if (newrule == NULL) {
3313				error = ENOMEM;
3314				break;
3315			}
3316			pf_rule_copyin(&pcr->rule, newrule, p, minordev);
3317#if !INET
3318			if (newrule->af == AF_INET) {
3319				pool_put(&pf_rule_pl, newrule);
3320				error = EAFNOSUPPORT;
3321				break;
3322			}
3323#endif /* INET */
3324#if !INET6
3325			if (newrule->af == AF_INET6) {
3326				pool_put(&pf_rule_pl, newrule);
3327				error = EAFNOSUPPORT;
3328				break;
3329			}
3330#endif /* INET6 */
3331			if (newrule->ifname[0]) {
3332				newrule->kif = pfi_kif_get(newrule->ifname);
3333				if (newrule->kif == NULL) {
3334					pool_put(&pf_rule_pl, newrule);
3335					error = EINVAL;
3336					break;
3337				}
3338				pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
3339			} else
3340				newrule->kif = NULL;
3341
3342#if PF_ALTQ
3343			/* set queue IDs */
3344			if (altq_allowed && newrule->qname[0] != '\0') {
3345				if ((newrule->qid =
3346				    pf_qname2qid(newrule->qname)) == 0)
3347					error = EBUSY;
3348				else if (newrule->pqname[0] != '\0') {
3349					if ((newrule->pqid =
3350					    pf_qname2qid(newrule->pqname)) == 0)
3351						error = EBUSY;
3352				} else
3353					newrule->pqid = newrule->qid;
3354			}
3355#endif /* PF_ALTQ */
3356			if (newrule->tagname[0])
3357				if ((newrule->tag =
3358				    pf_tagname2tag(newrule->tagname)) == 0)
3359					error = EBUSY;
3360			if (newrule->match_tagname[0])
3361				if ((newrule->match_tag = pf_tagname2tag(
3362				    newrule->match_tagname)) == 0)
3363					error = EBUSY;
3364			if (newrule->rt && !newrule->direction)
3365				error = EINVAL;
3366#if PFLOG
3367			if (!newrule->log)
3368				newrule->logif = 0;
3369			if (newrule->logif >= PFLOGIFS_MAX)
3370				error = EINVAL;
3371#endif /* PFLOG */
3372			pf_addrwrap_setup(&newrule->src.addr);
3373			pf_addrwrap_setup(&newrule->dst.addr);
3374			if (pf_rtlabel_add(&newrule->src.addr) ||
3375			    pf_rtlabel_add(&newrule->dst.addr))
3376				error = EBUSY;
3377			if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af))
3378				error = EINVAL;
3379			if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af))
3380				error = EINVAL;
3381			if (pf_tbladdr_setup(ruleset, &newrule->src.addr))
3382				error = EINVAL;
3383			if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))
3384				error = EINVAL;
3385			if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call))
3386				error = EINVAL;
3387			TAILQ_FOREACH(pa, &pf_pabuf, entries)
3388				if (pf_tbladdr_setup(ruleset, &pa->addr))
3389					error = EINVAL;
3390
3391			if (newrule->overload_tblname[0]) {
3392				if ((newrule->overload_tbl = pfr_attach_table(
3393				    ruleset, newrule->overload_tblname)) ==
3394				    NULL)
3395					error = EINVAL;
3396				else
3397					newrule->overload_tbl->pfrkt_flags |=
3398					    PFR_TFLAG_ACTIVE;
3399			}
3400
3401			pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
3402			if (((((newrule->action == PF_NAT) ||
3403			    (newrule->action == PF_RDR) ||
3404			    (newrule->action == PF_BINAT) ||
3405			    (newrule->rt > PF_FASTROUTE)) &&
3406			    !newrule->anchor)) &&
3407			    (TAILQ_FIRST(&newrule->rpool.list) == NULL))
3408				error = EINVAL;
3409
3410			if (error) {
3411				pf_rm_rule(NULL, newrule);
3412				break;
3413			}
3414			newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
3415			newrule->evaluations = 0;
3416			newrule->packets[0] = newrule->packets[1] = 0;
3417			newrule->bytes[0] = newrule->bytes[1] = 0;
3418		}
3419		pf_empty_pool(&pf_pabuf);
3420
3421		if (pcr->action == PF_CHANGE_ADD_HEAD)
3422			oldrule = TAILQ_FIRST(
3423			    ruleset->rules[rs_num].active.ptr);
3424		else if (pcr->action == PF_CHANGE_ADD_TAIL)
3425			oldrule = TAILQ_LAST(
3426			    ruleset->rules[rs_num].active.ptr, pf_rulequeue);
3427		else {
3428			oldrule = TAILQ_FIRST(
3429			    ruleset->rules[rs_num].active.ptr);
3430			while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
3431				oldrule = TAILQ_NEXT(oldrule, entries);
3432			if (oldrule == NULL) {
3433				if (newrule != NULL)
3434					pf_rm_rule(NULL, newrule);
3435				error = EINVAL;
3436				break;
3437			}
3438		}
3439
3440		if (pcr->action == PF_CHANGE_REMOVE) {
3441			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
3442			ruleset->rules[rs_num].active.rcount--;
3443		} else {
3444			if (oldrule == NULL)
3445				TAILQ_INSERT_TAIL(
3446				    ruleset->rules[rs_num].active.ptr,
3447				    newrule, entries);
3448			else if (pcr->action == PF_CHANGE_ADD_HEAD ||
3449			    pcr->action == PF_CHANGE_ADD_BEFORE)
3450				TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
3451			else
3452				TAILQ_INSERT_AFTER(
3453				    ruleset->rules[rs_num].active.ptr,
3454				    oldrule, newrule, entries);
3455			ruleset->rules[rs_num].active.rcount++;
3456		}
3457
3458		nr = 0;
3459		TAILQ_FOREACH(oldrule,
3460		    ruleset->rules[rs_num].active.ptr, entries)
3461			oldrule->nr = nr++;
3462
3463		ruleset->rules[rs_num].active.ticket++;
3464
3465		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
3466		pf_remove_if_empty_ruleset(ruleset);
3467
3468		break;
3469	}
3470
3471	case DIOCINSERTRULE: {
3472		struct pf_ruleset	*ruleset;
3473		struct pf_rule		*rule, *tail, *r;
3474		int			rs_num;
3475		int			is_anchor;
3476
3477		pr->anchor[sizeof (pr->anchor) - 1] = '\0';
3478		pr->anchor_call[sizeof (pr->anchor_call) - 1] = '\0';
3479		is_anchor = (pr->anchor_call[0] != '\0');
3480
3481		if ((ruleset = pf_find_ruleset_with_owner(pr->anchor,
3482		    pr->rule.owner, is_anchor, &error)) == NULL)
3483			break;
3484
3485		rs_num = pf_get_ruleset_number(pr->rule.action);
3486		if (rs_num >= PF_RULESET_MAX) {
3487			error = EINVAL;
3488			break;
3489		}
3490		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3491			error = EINVAL;
3492			break;
3493		}
3494
3495		/* make sure this anchor rule doesn't exist already */
3496		if (is_anchor) {
3497			r = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
3498			while (r) {
3499				if (r->anchor &&
3500				    ((strcmp(r->anchor->name,
3501				    pr->anchor_call)) == 0)) {
3502					if (((strcmp(pr->rule.owner,
3503					    r->owner)) == 0) ||
3504					    ((strcmp(r->owner, "")) == 0))
3505						error = EEXIST;
3506					else
3507						error = EPERM;
3508					break;
3509				}
3510				r = TAILQ_NEXT(r, entries);
3511			}
3512			if (error != 0)
3513				return (error);
3514		}
3515
3516		rule = pool_get(&pf_rule_pl, PR_WAITOK);
3517		if (rule == NULL) {
3518			error = ENOMEM;
3519			break;
3520		}
3521		pf_rule_copyin(&pr->rule, rule, p, minordev);
3522#if !INET
3523		if (rule->af == AF_INET) {
3524			pool_put(&pf_rule_pl, rule);
3525			error = EAFNOSUPPORT;
3526			break;
3527		}
3528#endif /* INET */
3529#if !INET6
3530		if (rule->af == AF_INET6) {
3531			pool_put(&pf_rule_pl, rule);
3532			error = EAFNOSUPPORT;
3533			break;
3534		}
3535
3536#endif /* INET6 */
3537		r = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
3538		while ((r != NULL) && (rule->priority >= (unsigned)r->priority))
3539			r = TAILQ_NEXT(r, entries);
3540		if (r == NULL) {
3541			if ((tail =
3542			    TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
3543			    pf_rulequeue)) != NULL)
3544				rule->nr = tail->nr + 1;
3545			else
3546				rule->nr = 0;
3547		} else {
3548			rule->nr = r->nr;
3549		}
3550
3551		if ((error = pf_rule_setup(pr, rule, ruleset)))
3552			break;
3553
3554		if (rule->anchor != NULL)
3555			strlcpy(rule->anchor->owner, rule->owner,
3556			    PF_OWNER_NAME_SIZE);
3557
3558		if (r) {
3559			TAILQ_INSERT_BEFORE(r, rule, entries);
3560			while (r && ++r->nr)
3561				r = TAILQ_NEXT(r, entries);
3562		} else
3563			TAILQ_INSERT_TAIL(ruleset->rules[rs_num].active.ptr,
3564			    rule, entries);
3565		ruleset->rules[rs_num].active.rcount++;
3566
3567		/* Calculate checksum for the main ruleset */
3568		if (ruleset == &pf_main_ruleset)
3569			error = pf_setup_pfsync_matching(ruleset);
3570
3571		pf_ruleset_cleanup(ruleset, rs_num);
3572		rule->ticket = VM_KERNEL_ADDRPERM((u_int64_t)(uintptr_t)rule);
3573
3574		pr->rule.ticket = rule->ticket;
3575		pf_rule_copyout(rule, &pr->rule);
3576		if (rule->rule_flag & PFRULE_PFM)
3577			pffwrules++;
3578		break;
3579	}
3580
3581	case DIOCDELETERULE: {
3582		pr->anchor[sizeof (pr->anchor) - 1] = '\0';
3583		pr->anchor_call[sizeof (pr->anchor_call) - 1] = '\0';
3584
3585		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
3586			error = EINVAL;
3587			break;
3588		}
3589
3590		/* get device through which request is made */
3591		if ((uint8_t)minordev == PFDEV_PFM)
3592			req_dev |= PFRULE_PFM;
3593
3594		if (pr->rule.ticket) {
3595			if ((error = pf_delete_rule_by_ticket(pr, req_dev)))
3596				break;
3597		} else
3598			pf_delete_rule_by_owner(pr->rule.owner, req_dev);
3599		pr->nr = pffwrules;
3600		break;
3601	}
3602
3603	default:
3604		VERIFY(0);
3605		/* NOTREACHED */
3606	}
3607
3608	return (error);
3609}
3610
3611static int
3612pfioctl_ioc_state_kill(u_long cmd, struct pfioc_state_kill *psk, struct proc *p)
3613{
3614#pragma unused(p)
3615	int error = 0;
3616
3617	psk->psk_ifname[sizeof (psk->psk_ifname) - 1] = '\0';
3618	psk->psk_ownername[sizeof(psk->psk_ownername) - 1] = '\0';
3619
3620	bool ifname_matched = true;
3621	bool owner_matched = true;
3622
3623	switch (cmd) {
3624	case DIOCCLRSTATES: {
3625		struct pf_state		*s, *nexts;
3626		int			 killed = 0;
3627
3628		for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) {
3629			nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
3630			/*
3631			 * Purge all states only when neither ifname
3632			 * or owner is provided. If any of these are provided
3633			 * we purge only the states with meta data that match
3634			 */
3635			bool unlink_state = false;
3636			ifname_matched = true;
3637			owner_matched = true;
3638
3639			if (psk->psk_ifname[0] &&
3640			    strcmp(psk->psk_ifname, s->kif->pfik_name)) {
3641				ifname_matched = false;
3642			}
3643
3644			if (psk->psk_ownername[0] &&
3645			    ((NULL == s->rule.ptr) ||
3646			     strcmp(psk->psk_ownername, s->rule.ptr->owner))) {
3647				owner_matched = false;
3648			}
3649
3650			unlink_state = ifname_matched && owner_matched;
3651
3652			if (unlink_state) {
3653#if NPFSYNC
3654				/* don't send out individual delete messages */
3655				s->sync_flags = PFSTATE_NOSYNC;
3656#endif
3657				pf_unlink_state(s);
3658				killed++;
3659			}
3660		}
3661		psk->psk_af = killed;
3662#if NPFSYNC
3663		pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
3664#endif
3665		break;
3666	}
3667
3668	case DIOCKILLSTATES: {
3669		struct pf_state		*s, *nexts;
3670		struct pf_state_key	*sk;
3671		struct pf_state_host	*src, *dst;
3672		int			 killed = 0;
3673
3674		for (s = RB_MIN(pf_state_tree_id, &tree_id); s;
3675		    s = nexts) {
3676			nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
3677			sk = s->state_key;
3678			ifname_matched = true;
3679			owner_matched = true;
3680
3681			if (psk->psk_ifname[0] &&
3682			    strcmp(psk->psk_ifname, s->kif->pfik_name)) {
3683				ifname_matched = false;
3684			}
3685
3686			if (psk->psk_ownername[0] &&
3687			    ((NULL == s->rule.ptr) ||
3688			     strcmp(psk->psk_ownername, s->rule.ptr->owner))) {
3689				owner_matched = false;
3690			}
3691
3692			if (sk->direction == PF_OUT) {
3693				src = &sk->lan;
3694				dst = &sk->ext;
3695			} else {
3696				src = &sk->ext;
3697				dst = &sk->lan;
3698			}
3699			if ((!psk->psk_af || sk->af == psk->psk_af) &&
3700			    (!psk->psk_proto || psk->psk_proto == sk->proto) &&
3701			    PF_MATCHA(psk->psk_src.neg,
3702			    &psk->psk_src.addr.v.a.addr,
3703			    &psk->psk_src.addr.v.a.mask,
3704			    &src->addr, sk->af) &&
3705			    PF_MATCHA(psk->psk_dst.neg,
3706			    &psk->psk_dst.addr.v.a.addr,
3707			    &psk->psk_dst.addr.v.a.mask,
3708			    &dst->addr, sk->af) &&
3709			    (pf_match_xport(psk->psk_proto,
3710			    psk->psk_proto_variant, &psk->psk_src.xport,
3711			    &src->xport)) &&
3712			    (pf_match_xport(psk->psk_proto,
3713			    psk->psk_proto_variant, &psk->psk_dst.xport,
3714			    &dst->xport)) &&
3715			    ifname_matched &&
3716			    owner_matched) {
3717#if NPFSYNC
3718				/* send immediate delete of state */
3719				pfsync_delete_state(s);
3720				s->sync_flags |= PFSTATE_NOSYNC;
3721#endif
3722				pf_unlink_state(s);
3723				killed++;
3724			}
3725		}
3726		psk->psk_af = killed;
3727		break;
3728	}
3729
3730	default:
3731		VERIFY(0);
3732		/* NOTREACHED */
3733	}
3734
3735	return (error);
3736}
3737
3738static int
3739pfioctl_ioc_state(u_long cmd, struct pfioc_state *ps, struct proc *p)
3740{
3741#pragma unused(p)
3742	int error = 0;
3743
3744	switch (cmd) {
3745	case DIOCADDSTATE: {
3746		struct pfsync_state	*sp = &ps->state;
3747		struct pf_state		*s;
3748		struct pf_state_key	*sk;
3749		struct pfi_kif		*kif;
3750
3751		if (sp->timeout >= PFTM_MAX) {
3752			error = EINVAL;
3753			break;
3754		}
3755		s = pool_get(&pf_state_pl, PR_WAITOK);
3756		if (s == NULL) {
3757			error = ENOMEM;
3758			break;
3759		}
3760		bzero(s, sizeof (struct pf_state));
3761		if ((sk = pf_alloc_state_key(s, NULL)) == NULL) {
3762			pool_put(&pf_state_pl, s);
3763			error = ENOMEM;
3764			break;
3765		}
3766		pf_state_import(sp, sk, s);
3767		kif = pfi_kif_get(sp->ifname);
3768		if (kif == NULL) {
3769			pool_put(&pf_state_pl, s);
3770			pool_put(&pf_state_key_pl, sk);
3771			error = ENOENT;
3772			break;
3773		}
3774		TAILQ_INIT(&s->unlink_hooks);
3775		s->state_key->app_state = 0;
3776		if (pf_insert_state(kif, s)) {
3777			pfi_kif_unref(kif, PFI_KIF_REF_NONE);
3778			pool_put(&pf_state_pl, s);
3779			error = EEXIST;
3780			break;
3781		}
3782		pf_default_rule.states++;
3783		VERIFY(pf_default_rule.states != 0);
3784		break;
3785	}
3786
3787	case DIOCGETSTATE: {
3788		struct pf_state		*s;
3789		struct pf_state_cmp	 id_key;
3790
3791		bcopy(ps->state.id, &id_key.id, sizeof (id_key.id));
3792		id_key.creatorid = ps->state.creatorid;
3793
3794		s = pf_find_state_byid(&id_key);
3795		if (s == NULL) {
3796			error = ENOENT;
3797			break;
3798		}
3799
3800		pf_state_export(&ps->state, s->state_key, s);
3801		break;
3802	}
3803
3804	default:
3805		VERIFY(0);
3806		/* NOTREACHED */
3807	}
3808
3809	return (error);
3810}
3811
3812static int
3813pfioctl_ioc_states(u_long cmd, struct pfioc_states_32 *ps32,
3814    struct pfioc_states_64 *ps64, struct proc *p)
3815{
3816	int p64 = proc_is64bit(p);
3817	int error = 0;
3818
3819	switch (cmd) {
3820	case DIOCGETSTATES: {		/* struct pfioc_states */
3821		struct pf_state		*state;
3822		struct pfsync_state	*pstore;
3823		user_addr_t		 buf;
3824		u_int32_t		 nr = 0;
3825		int			 len, size;
3826
3827		len = (p64 ? ps64->ps_len : ps32->ps_len);
3828		if (len == 0) {
3829			size = sizeof (struct pfsync_state) * pf_status.states;
3830			if (p64)
3831				ps64->ps_len = size;
3832			else
3833				ps32->ps_len = size;
3834			break;
3835		}
3836
3837		pstore = _MALLOC(sizeof (*pstore), M_TEMP, M_WAITOK);
3838		if (pstore == NULL) {
3839			error = ENOMEM;
3840			break;
3841		}
3842		buf = (p64 ? ps64->ps_buf : ps32->ps_buf);
3843
3844		state = TAILQ_FIRST(&state_list);
3845		while (state) {
3846			if (state->timeout != PFTM_UNLINKED) {
3847				if ((nr + 1) * sizeof (*pstore) > (unsigned)len)
3848					break;
3849
3850				pf_state_export(pstore,
3851				    state->state_key, state);
3852				error = copyout(pstore, buf, sizeof (*pstore));
3853				if (error) {
3854					_FREE(pstore, M_TEMP);
3855					goto fail;
3856				}
3857				buf += sizeof (*pstore);
3858				nr++;
3859			}
3860			state = TAILQ_NEXT(state, entry_list);
3861		}
3862
3863		size = sizeof (struct pfsync_state) * nr;
3864		if (p64)
3865			ps64->ps_len = size;
3866		else
3867			ps32->ps_len = size;
3868
3869		_FREE(pstore, M_TEMP);
3870		break;
3871	}
3872
3873	default:
3874		VERIFY(0);
3875		/* NOTREACHED */
3876	}
3877fail:
3878	return (error);
3879}
3880
3881static int
3882pfioctl_ioc_natlook(u_long cmd, struct pfioc_natlook *pnl, struct proc *p)
3883{
3884#pragma unused(p)
3885	int error = 0;
3886
3887	switch (cmd) {
3888	case DIOCNATLOOK: {
3889		struct pf_state_key	*sk;
3890		struct pf_state		*state;
3891		struct pf_state_key_cmp	 key;
3892		int			 m = 0, direction = pnl->direction;
3893
3894		key.af = pnl->af;
3895		key.proto = pnl->proto;
3896		key.proto_variant = pnl->proto_variant;
3897
3898		if (!pnl->proto ||
3899		    PF_AZERO(&pnl->saddr, pnl->af) ||
3900		    PF_AZERO(&pnl->daddr, pnl->af) ||
3901		    ((pnl->proto == IPPROTO_TCP ||
3902		    pnl->proto == IPPROTO_UDP) &&
3903		    (!pnl->dxport.port || !pnl->sxport.port)))
3904			error = EINVAL;
3905		else {
3906			/*
3907			 * userland gives us source and dest of connection,
3908			 * reverse the lookup so we ask for what happens with
3909			 * the return traffic, enabling us to find it in the
3910			 * state tree.
3911			 */
3912			if (direction == PF_IN) {
3913				PF_ACPY(&key.ext.addr, &pnl->daddr, pnl->af);
3914				memcpy(&key.ext.xport, &pnl->dxport,
3915				    sizeof (key.ext.xport));
3916				PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af);
3917				memcpy(&key.gwy.xport, &pnl->sxport,
3918				    sizeof (key.gwy.xport));
3919				state = pf_find_state_all(&key, PF_IN, &m);
3920			} else {
3921				PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af);
3922				memcpy(&key.lan.xport, &pnl->dxport,
3923				    sizeof (key.lan.xport));
3924				PF_ACPY(&key.ext.addr, &pnl->saddr, pnl->af);
3925				memcpy(&key.ext.xport, &pnl->sxport,
3926				    sizeof (key.ext.xport));
3927				state = pf_find_state_all(&key, PF_OUT, &m);
3928			}
3929			if (m > 1)
3930				error = E2BIG;	/* more than one state */
3931			else if (state != NULL) {
3932				sk = state->state_key;
3933				if (direction == PF_IN) {
3934					PF_ACPY(&pnl->rsaddr, &sk->lan.addr,
3935					    sk->af);
3936					memcpy(&pnl->rsxport, &sk->lan.xport,
3937					    sizeof (pnl->rsxport));
3938					PF_ACPY(&pnl->rdaddr, &pnl->daddr,
3939					    pnl->af);
3940					memcpy(&pnl->rdxport, &pnl->dxport,
3941					    sizeof (pnl->rdxport));
3942				} else {
3943					PF_ACPY(&pnl->rdaddr, &sk->gwy.addr,
3944					    sk->af);
3945					memcpy(&pnl->rdxport, &sk->gwy.xport,
3946					    sizeof (pnl->rdxport));
3947					PF_ACPY(&pnl->rsaddr, &pnl->saddr,
3948					    pnl->af);
3949					memcpy(&pnl->rsxport, &pnl->sxport,
3950					    sizeof (pnl->rsxport));
3951				}
3952			} else
3953				error = ENOENT;
3954		}
3955		break;
3956	}
3957
3958	default:
3959		VERIFY(0);
3960		/* NOTREACHED */
3961	}
3962
3963	return (error);
3964}
3965
3966static int
3967pfioctl_ioc_tm(u_long cmd, struct pfioc_tm *pt, struct proc *p)
3968{
3969#pragma unused(p)
3970	int error = 0;
3971
3972	switch (cmd) {
3973	case DIOCSETTIMEOUT: {
3974		int old;
3975
3976		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
3977		    pt->seconds < 0) {
3978			error = EINVAL;
3979			goto fail;
3980		}
3981		old = pf_default_rule.timeout[pt->timeout];
3982		if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
3983			pt->seconds = 1;
3984		pf_default_rule.timeout[pt->timeout] = pt->seconds;
3985		if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
3986			wakeup(pf_purge_thread_fn);
3987		pt->seconds = old;
3988		break;
3989	}
3990
3991	case DIOCGETTIMEOUT: {
3992		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
3993			error = EINVAL;
3994			goto fail;
3995		}
3996		pt->seconds = pf_default_rule.timeout[pt->timeout];
3997		break;
3998	}
3999
4000	default:
4001		VERIFY(0);
4002		/* NOTREACHED */
4003	}
4004fail:
4005	return (error);
4006}
4007
4008static int
4009pfioctl_ioc_limit(u_long cmd, struct pfioc_limit *pl, struct proc *p)
4010{
4011#pragma unused(p)
4012	int error = 0;
4013
4014	switch (cmd) {
4015	case DIOCGETLIMIT: {
4016
4017		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
4018			error = EINVAL;
4019			goto fail;
4020		}
4021		pl->limit = pf_pool_limits[pl->index].limit;
4022		break;
4023	}
4024
4025	case DIOCSETLIMIT: {
4026		int old_limit;
4027
4028		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
4029		    pf_pool_limits[pl->index].pp == NULL) {
4030			error = EINVAL;
4031			goto fail;
4032		}
4033		pool_sethardlimit(pf_pool_limits[pl->index].pp,
4034		    pl->limit, NULL, 0);
4035		old_limit = pf_pool_limits[pl->index].limit;
4036		pf_pool_limits[pl->index].limit = pl->limit;
4037		pl->limit = old_limit;
4038		break;
4039	}
4040
4041	default:
4042		VERIFY(0);
4043		/* NOTREACHED */
4044	}
4045fail:
4046	return (error);
4047}
4048
4049static int
4050pfioctl_ioc_pooladdr(u_long cmd, struct pfioc_pooladdr *pp, struct proc *p)
4051{
4052#pragma unused(p)
4053	struct pf_pooladdr *pa = NULL;
4054	struct pf_pool *pool = NULL;
4055	int error = 0;
4056
4057	switch (cmd) {
4058	case DIOCBEGINADDRS: {
4059		pf_empty_pool(&pf_pabuf);
4060		pp->ticket = ++ticket_pabuf;
4061		break;
4062	}
4063
4064	case DIOCADDADDR: {
4065		pp->anchor[sizeof (pp->anchor) - 1] = '\0';
4066		if (pp->ticket != ticket_pabuf) {
4067			error = EBUSY;
4068			break;
4069		}
4070#if !INET
4071		if (pp->af == AF_INET) {
4072			error = EAFNOSUPPORT;
4073			break;
4074		}
4075#endif /* INET */
4076#if !INET6
4077		if (pp->af == AF_INET6) {
4078			error = EAFNOSUPPORT;
4079			break;
4080		}
4081#endif /* INET6 */
4082		if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
4083		    pp->addr.addr.type != PF_ADDR_DYNIFTL &&
4084		    pp->addr.addr.type != PF_ADDR_TABLE) {
4085			error = EINVAL;
4086			break;
4087		}
4088		pa = pool_get(&pf_pooladdr_pl, PR_WAITOK);
4089		if (pa == NULL) {
4090			error = ENOMEM;
4091			break;
4092		}
4093		pf_pooladdr_copyin(&pp->addr, pa);
4094		if (pa->ifname[0]) {
4095			pa->kif = pfi_kif_get(pa->ifname);
4096			if (pa->kif == NULL) {
4097				pool_put(&pf_pooladdr_pl, pa);
4098				error = EINVAL;
4099				break;
4100			}
4101			pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
4102		}
4103		pf_addrwrap_setup(&pa->addr);
4104		if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
4105			pfi_dynaddr_remove(&pa->addr);
4106			pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
4107			pool_put(&pf_pooladdr_pl, pa);
4108			error = EINVAL;
4109			break;
4110		}
4111		TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
4112		break;
4113	}
4114
4115	case DIOCGETADDRS: {
4116		pp->nr = 0;
4117		pp->anchor[sizeof (pp->anchor) - 1] = '\0';
4118		pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
4119		    pp->r_num, 0, 1, 0);
4120		if (pool == NULL) {
4121			error = EBUSY;
4122			break;
4123		}
4124		TAILQ_FOREACH(pa, &pool->list, entries)
4125			pp->nr++;
4126		break;
4127	}
4128
4129	case DIOCGETADDR: {
4130		u_int32_t		 nr = 0;
4131
4132		pp->anchor[sizeof (pp->anchor) - 1] = '\0';
4133		pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
4134		    pp->r_num, 0, 1, 1);
4135		if (pool == NULL) {
4136			error = EBUSY;
4137			break;
4138		}
4139		pa = TAILQ_FIRST(&pool->list);
4140		while ((pa != NULL) && (nr < pp->nr)) {
4141			pa = TAILQ_NEXT(pa, entries);
4142			nr++;
4143		}
4144		if (pa == NULL) {
4145			error = EBUSY;
4146			break;
4147		}
4148		pf_pooladdr_copyout(pa, &pp->addr);
4149		pfi_dynaddr_copyout(&pp->addr.addr);
4150		pf_tbladdr_copyout(&pp->addr.addr);
4151		pf_rtlabel_copyout(&pp->addr.addr);
4152		break;
4153	}
4154
4155	case DIOCCHANGEADDR: {
4156		struct pfioc_pooladdr	*pca = pp;
4157		struct pf_pooladdr	*oldpa = NULL, *newpa = NULL;
4158		struct pf_ruleset	*ruleset;
4159
4160		if (pca->action < PF_CHANGE_ADD_HEAD ||
4161		    pca->action > PF_CHANGE_REMOVE) {
4162			error = EINVAL;
4163			break;
4164		}
4165		if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
4166		    pca->addr.addr.type != PF_ADDR_DYNIFTL &&
4167		    pca->addr.addr.type != PF_ADDR_TABLE) {
4168			error = EINVAL;
4169			break;
4170		}
4171
4172		pca->anchor[sizeof (pca->anchor) - 1] = '\0';
4173		ruleset = pf_find_ruleset(pca->anchor);
4174		if (ruleset == NULL) {
4175			error = EBUSY;
4176			break;
4177		}
4178		pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
4179		    pca->r_num, pca->r_last, 1, 1);
4180		if (pool == NULL) {
4181			error = EBUSY;
4182			break;
4183		}
4184		if (pca->action != PF_CHANGE_REMOVE) {
4185			newpa = pool_get(&pf_pooladdr_pl, PR_WAITOK);
4186			if (newpa == NULL) {
4187				error = ENOMEM;
4188				break;
4189			}
4190			pf_pooladdr_copyin(&pca->addr, newpa);
4191#if !INET
4192			if (pca->af == AF_INET) {
4193				pool_put(&pf_pooladdr_pl, newpa);
4194				error = EAFNOSUPPORT;
4195				break;
4196			}
4197#endif /* INET */
4198#if !INET6
4199			if (pca->af == AF_INET6) {
4200				pool_put(&pf_pooladdr_pl, newpa);
4201				error = EAFNOSUPPORT;
4202				break;
4203			}
4204#endif /* INET6 */
4205			if (newpa->ifname[0]) {
4206				newpa->kif = pfi_kif_get(newpa->ifname);
4207				if (newpa->kif == NULL) {
4208					pool_put(&pf_pooladdr_pl, newpa);
4209					error = EINVAL;
4210					break;
4211				}
4212				pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
4213			} else
4214				newpa->kif = NULL;
4215			pf_addrwrap_setup(&newpa->addr);
4216			if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
4217			    pf_tbladdr_setup(ruleset, &newpa->addr)) {
4218				pfi_dynaddr_remove(&newpa->addr);
4219				pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
4220				pool_put(&pf_pooladdr_pl, newpa);
4221				error = EINVAL;
4222				break;
4223			}
4224		}
4225
4226		if (pca->action == PF_CHANGE_ADD_HEAD)
4227			oldpa = TAILQ_FIRST(&pool->list);
4228		else if (pca->action == PF_CHANGE_ADD_TAIL)
4229			oldpa = TAILQ_LAST(&pool->list, pf_palist);
4230		else {
4231			int	i = 0;
4232
4233			oldpa = TAILQ_FIRST(&pool->list);
4234			while ((oldpa != NULL) && (i < (int)pca->nr)) {
4235				oldpa = TAILQ_NEXT(oldpa, entries);
4236				i++;
4237			}
4238			if (oldpa == NULL) {
4239				error = EINVAL;
4240				break;
4241			}
4242		}
4243
4244		if (pca->action == PF_CHANGE_REMOVE) {
4245			TAILQ_REMOVE(&pool->list, oldpa, entries);
4246			pfi_dynaddr_remove(&oldpa->addr);
4247			pf_tbladdr_remove(&oldpa->addr);
4248			pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
4249			pool_put(&pf_pooladdr_pl, oldpa);
4250		} else {
4251			if (oldpa == NULL)
4252				TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
4253			else if (pca->action == PF_CHANGE_ADD_HEAD ||
4254			    pca->action == PF_CHANGE_ADD_BEFORE)
4255				TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
4256			else
4257				TAILQ_INSERT_AFTER(&pool->list, oldpa,
4258				    newpa, entries);
4259		}
4260
4261		pool->cur = TAILQ_FIRST(&pool->list);
4262		PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
4263		    pca->af);
4264		break;
4265	}
4266
4267	default:
4268		VERIFY(0);
4269		/* NOTREACHED */
4270	}
4271
4272	return (error);
4273}
4274
4275static int
4276pfioctl_ioc_ruleset(u_long cmd, struct pfioc_ruleset *pr, struct proc *p)
4277{
4278#pragma unused(p)
4279	int error = 0;
4280
4281	switch (cmd) {
4282	case DIOCGETRULESETS: {
4283		struct pf_ruleset	*ruleset;
4284		struct pf_anchor	*anchor;
4285
4286		pr->path[sizeof (pr->path) - 1] = '\0';
4287		pr->name[sizeof (pr->name) - 1] = '\0';
4288		if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
4289			error = EINVAL;
4290			break;
4291		}
4292		pr->nr = 0;
4293		if (ruleset->anchor == NULL) {
4294			/* XXX kludge for pf_main_ruleset */
4295			RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
4296				if (anchor->parent == NULL)
4297					pr->nr++;
4298		} else {
4299			RB_FOREACH(anchor, pf_anchor_node,
4300			    &ruleset->anchor->children)
4301				pr->nr++;
4302		}
4303		break;
4304	}
4305
4306	case DIOCGETRULESET: {
4307		struct pf_ruleset	*ruleset;
4308		struct pf_anchor	*anchor;
4309		u_int32_t		 nr = 0;
4310
4311		pr->path[sizeof (pr->path) - 1] = '\0';
4312		if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
4313			error = EINVAL;
4314			break;
4315		}
4316		pr->name[0] = 0;
4317		if (ruleset->anchor == NULL) {
4318			/* XXX kludge for pf_main_ruleset */
4319			RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
4320				if (anchor->parent == NULL && nr++ == pr->nr) {
4321					strlcpy(pr->name, anchor->name,
4322					    sizeof (pr->name));
4323					break;
4324				}
4325		} else {
4326			RB_FOREACH(anchor, pf_anchor_node,
4327			    &ruleset->anchor->children)
4328				if (nr++ == pr->nr) {
4329					strlcpy(pr->name, anchor->name,
4330					    sizeof (pr->name));
4331					break;
4332				}
4333		}
4334		if (!pr->name[0])
4335			error = EBUSY;
4336		break;
4337	}
4338
4339	default:
4340		VERIFY(0);
4341		/* NOTREACHED */
4342	}
4343
4344	return (error);
4345}
4346
4347static int
4348pfioctl_ioc_trans(u_long cmd, struct pfioc_trans_32 *io32,
4349    struct pfioc_trans_64 *io64, struct proc *p)
4350{
4351	int p64 = proc_is64bit(p);
4352	int error = 0, esize, size;
4353	user_addr_t buf;
4354
4355	esize = (p64 ? io64->esize : io32->esize);
4356	size = (p64 ? io64->size : io32->size);
4357	buf = (p64 ? io64->array : io32->array);
4358
4359	switch (cmd) {
4360	case DIOCXBEGIN: {
4361		struct pfioc_trans_e	*ioe;
4362		struct pfr_table	*table;
4363		int			 i;
4364
4365		if (esize != sizeof (*ioe)) {
4366			error = ENODEV;
4367			goto fail;
4368		}
4369		ioe = _MALLOC(sizeof (*ioe), M_TEMP, M_WAITOK);
4370		table = _MALLOC(sizeof (*table), M_TEMP, M_WAITOK);
4371		for (i = 0; i < size; i++, buf += sizeof (*ioe)) {
4372			if (copyin(buf, ioe, sizeof (*ioe))) {
4373				_FREE(table, M_TEMP);
4374				_FREE(ioe, M_TEMP);
4375				error = EFAULT;
4376				goto fail;
4377			}
4378			ioe->anchor[sizeof (ioe->anchor) - 1] = '\0';
4379			switch (ioe->rs_num) {
4380			case PF_RULESET_ALTQ:
4381#if PF_ALTQ
4382				if (altq_allowed) {
4383					if (ioe->anchor[0]) {
4384						_FREE(table, M_TEMP);
4385						_FREE(ioe, M_TEMP);
4386						error = EINVAL;
4387						goto fail;
4388					}
4389					error = pf_begin_altq(&ioe->ticket);
4390					if (error != 0) {
4391						_FREE(table, M_TEMP);
4392						_FREE(ioe, M_TEMP);
4393						goto fail;
4394					}
4395				}
4396#endif /* PF_ALTQ */
4397				break;
4398			case PF_RULESET_TABLE:
4399				bzero(table, sizeof (*table));
4400				strlcpy(table->pfrt_anchor, ioe->anchor,
4401				    sizeof (table->pfrt_anchor));
4402				if ((error = pfr_ina_begin(table,
4403				    &ioe->ticket, NULL, 0))) {
4404					_FREE(table, M_TEMP);
4405					_FREE(ioe, M_TEMP);
4406					goto fail;
4407				}
4408				break;
4409			default:
4410				if ((error = pf_begin_rules(&ioe->ticket,
4411				    ioe->rs_num, ioe->anchor))) {
4412					_FREE(table, M_TEMP);
4413					_FREE(ioe, M_TEMP);
4414					goto fail;
4415				}
4416				break;
4417			}
4418			if (copyout(ioe, buf, sizeof (*ioe))) {
4419				_FREE(table, M_TEMP);
4420				_FREE(ioe, M_TEMP);
4421				error = EFAULT;
4422				goto fail;
4423			}
4424		}
4425		_FREE(table, M_TEMP);
4426		_FREE(ioe, M_TEMP);
4427		break;
4428	}
4429
4430	case DIOCXROLLBACK: {
4431		struct pfioc_trans_e	*ioe;
4432		struct pfr_table	*table;
4433		int			 i;
4434
4435		if (esize != sizeof (*ioe)) {
4436			error = ENODEV;
4437			goto fail;
4438		}
4439		ioe = _MALLOC(sizeof (*ioe), M_TEMP, M_WAITOK);
4440		table = _MALLOC(sizeof (*table), M_TEMP, M_WAITOK);
4441		for (i = 0; i < size; i++, buf += sizeof (*ioe)) {
4442			if (copyin(buf, ioe, sizeof (*ioe))) {
4443				_FREE(table, M_TEMP);
4444				_FREE(ioe, M_TEMP);
4445				error = EFAULT;
4446				goto fail;
4447			}
4448			ioe->anchor[sizeof (ioe->anchor) - 1] = '\0';
4449			switch (ioe->rs_num) {
4450			case PF_RULESET_ALTQ:
4451#if PF_ALTQ
4452				if (altq_allowed) {
4453					if (ioe->anchor[0]) {
4454						_FREE(table, M_TEMP);
4455						_FREE(ioe, M_TEMP);
4456						error = EINVAL;
4457						goto fail;
4458					}
4459					error = pf_rollback_altq(ioe->ticket);
4460					if (error != 0) {
4461						_FREE(table, M_TEMP);
4462						_FREE(ioe, M_TEMP);
4463						goto fail; /* really bad */
4464					}
4465				}
4466#endif /* PF_ALTQ */
4467				break;
4468			case PF_RULESET_TABLE:
4469				bzero(table, sizeof (*table));
4470				strlcpy(table->pfrt_anchor, ioe->anchor,
4471				    sizeof (table->pfrt_anchor));
4472				if ((error = pfr_ina_rollback(table,
4473				    ioe->ticket, NULL, 0))) {
4474					_FREE(table, M_TEMP);
4475					_FREE(ioe, M_TEMP);
4476					goto fail; /* really bad */
4477				}
4478				break;
4479			default:
4480				if ((error = pf_rollback_rules(ioe->ticket,
4481				    ioe->rs_num, ioe->anchor))) {
4482					_FREE(table, M_TEMP);
4483					_FREE(ioe, M_TEMP);
4484					goto fail; /* really bad */
4485				}
4486				break;
4487			}
4488		}
4489		_FREE(table, M_TEMP);
4490		_FREE(ioe, M_TEMP);
4491		break;
4492	}
4493
4494	case DIOCXCOMMIT: {
4495		struct pfioc_trans_e	*ioe;
4496		struct pfr_table	*table;
4497		struct pf_ruleset	*rs;
4498		user_addr_t		 _buf = buf;
4499		int			 i;
4500
4501		if (esize != sizeof (*ioe)) {
4502			error = ENODEV;
4503			goto fail;
4504		}
4505		ioe = _MALLOC(sizeof (*ioe), M_TEMP, M_WAITOK);
4506		table = _MALLOC(sizeof (*table), M_TEMP, M_WAITOK);
4507		/* first makes sure everything will succeed */
4508		for (i = 0; i < size; i++, buf += sizeof (*ioe)) {
4509			if (copyin(buf, ioe, sizeof (*ioe))) {
4510				_FREE(table, M_TEMP);
4511				_FREE(ioe, M_TEMP);
4512				error = EFAULT;
4513				goto fail;
4514			}
4515			ioe->anchor[sizeof (ioe->anchor) - 1] = '\0';
4516			switch (ioe->rs_num) {
4517			case PF_RULESET_ALTQ:
4518#if PF_ALTQ
4519				if (altq_allowed) {
4520					if (ioe->anchor[0]) {
4521						_FREE(table, M_TEMP);
4522						_FREE(ioe, M_TEMP);
4523						error = EINVAL;
4524						goto fail;
4525					}
4526					if (!altqs_inactive_open ||
4527					    ioe->ticket !=
4528					    ticket_altqs_inactive) {
4529						_FREE(table, M_TEMP);
4530						_FREE(ioe, M_TEMP);
4531						error = EBUSY;
4532						goto fail;
4533					}
4534				}
4535#endif /* PF_ALTQ */
4536				break;
4537			case PF_RULESET_TABLE:
4538				rs = pf_find_ruleset(ioe->anchor);
4539				if (rs == NULL || !rs->topen || ioe->ticket !=
4540				    rs->tticket) {
4541					_FREE(table, M_TEMP);
4542					_FREE(ioe, M_TEMP);
4543					error = EBUSY;
4544					goto fail;
4545				}
4546				break;
4547			default:
4548				if (ioe->rs_num < 0 || ioe->rs_num >=
4549				    PF_RULESET_MAX) {
4550					_FREE(table, M_TEMP);
4551					_FREE(ioe, M_TEMP);
4552					error = EINVAL;
4553					goto fail;
4554				}
4555				rs = pf_find_ruleset(ioe->anchor);
4556				if (rs == NULL ||
4557				    !rs->rules[ioe->rs_num].inactive.open ||
4558				    rs->rules[ioe->rs_num].inactive.ticket !=
4559				    ioe->ticket) {
4560					_FREE(table, M_TEMP);
4561					_FREE(ioe, M_TEMP);
4562					error = EBUSY;
4563					goto fail;
4564				}
4565				break;
4566			}
4567		}
4568		buf = _buf;
4569		/* now do the commit - no errors should happen here */
4570		for (i = 0; i < size; i++, buf += sizeof (*ioe)) {
4571			if (copyin(buf, ioe, sizeof (*ioe))) {
4572				_FREE(table, M_TEMP);
4573				_FREE(ioe, M_TEMP);
4574				error = EFAULT;
4575				goto fail;
4576			}
4577			ioe->anchor[sizeof (ioe->anchor) - 1] = '\0';
4578			switch (ioe->rs_num) {
4579			case PF_RULESET_ALTQ:
4580#if PF_ALTQ
4581				if (altq_allowed &&
4582				    (error = pf_commit_altq(ioe->ticket))) {
4583					_FREE(table, M_TEMP);
4584					_FREE(ioe, M_TEMP);
4585					goto fail; /* really bad */
4586				}
4587#endif /* PF_ALTQ */
4588				break;
4589			case PF_RULESET_TABLE:
4590				bzero(table, sizeof (*table));
4591				strlcpy(table->pfrt_anchor, ioe->anchor,
4592				    sizeof (table->pfrt_anchor));
4593				if ((error = pfr_ina_commit(table, ioe->ticket,
4594				    NULL, NULL, 0))) {
4595					_FREE(table, M_TEMP);
4596					_FREE(ioe, M_TEMP);
4597					goto fail; /* really bad */
4598				}
4599				break;
4600			default:
4601				if ((error = pf_commit_rules(ioe->ticket,
4602				    ioe->rs_num, ioe->anchor))) {
4603					_FREE(table, M_TEMP);
4604					_FREE(ioe, M_TEMP);
4605					goto fail; /* really bad */
4606				}
4607				break;
4608			}
4609		}
4610		_FREE(table, M_TEMP);
4611		_FREE(ioe, M_TEMP);
4612		break;
4613	}
4614
4615	default:
4616		VERIFY(0);
4617		/* NOTREACHED */
4618	}
4619fail:
4620	return (error);
4621}
4622
4623static int
4624pfioctl_ioc_src_nodes(u_long cmd, struct pfioc_src_nodes_32 *psn32,
4625    struct pfioc_src_nodes_64 *psn64, struct proc *p)
4626{
4627	int p64 = proc_is64bit(p);
4628	int error = 0;
4629
4630	switch (cmd) {
4631	case DIOCGETSRCNODES: {
4632		struct pf_src_node	*n, *pstore;
4633		user_addr_t		 buf;
4634		u_int32_t		 nr = 0;
4635		int			 space, size;
4636
4637		space = (p64 ? psn64->psn_len : psn32->psn_len);
4638		if (space == 0) {
4639			RB_FOREACH(n, pf_src_tree, &tree_src_tracking)
4640				nr++;
4641
4642			size = sizeof (struct pf_src_node) * nr;
4643			if (p64)
4644				psn64->psn_len = size;
4645			else
4646				psn32->psn_len = size;
4647			break;
4648		}
4649
4650		pstore = _MALLOC(sizeof (*pstore), M_TEMP, M_WAITOK);
4651		if (pstore == NULL) {
4652			error = ENOMEM;
4653			break;
4654		}
4655		buf = (p64 ? psn64->psn_buf : psn32->psn_buf);
4656
4657		RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
4658			uint64_t secs = pf_time_second(), diff;
4659
4660			if ((nr + 1) * sizeof (*pstore) > (unsigned)space)
4661				break;
4662
4663			bcopy(n, pstore, sizeof (*pstore));
4664			if (n->rule.ptr != NULL)
4665				pstore->rule.nr = n->rule.ptr->nr;
4666			pstore->creation = secs - pstore->creation;
4667			if (pstore->expire > secs)
4668				pstore->expire -= secs;
4669			else
4670				pstore->expire = 0;
4671
4672			/* adjust the connection rate estimate */
4673			diff = secs - n->conn_rate.last;
4674			if (diff >= n->conn_rate.seconds)
4675				pstore->conn_rate.count = 0;
4676			else
4677				pstore->conn_rate.count -=
4678				    n->conn_rate.count * diff /
4679				    n->conn_rate.seconds;
4680
4681			_RB_PARENT(pstore, entry) = NULL;
4682			RB_LEFT(pstore, entry) = RB_RIGHT(pstore, entry) = NULL;
4683			pstore->kif = NULL;
4684
4685			error = copyout(pstore, buf, sizeof (*pstore));
4686			if (error) {
4687				_FREE(pstore, M_TEMP);
4688				goto fail;
4689			}
4690			buf += sizeof (*pstore);
4691			nr++;
4692		}
4693
4694		size = sizeof (struct pf_src_node) * nr;
4695		if (p64)
4696			psn64->psn_len = size;
4697		else
4698			psn32->psn_len = size;
4699
4700		_FREE(pstore, M_TEMP);
4701		break;
4702	}
4703
4704	default:
4705		VERIFY(0);
4706		/* NOTREACHED */
4707	}
4708fail:
4709	return (error);
4710
4711}
4712
4713static int
4714pfioctl_ioc_src_node_kill(u_long cmd, struct pfioc_src_node_kill *psnk,
4715    struct proc *p)
4716{
4717#pragma unused(p)
4718	int error = 0;
4719
4720	switch (cmd) {
4721	case DIOCKILLSRCNODES: {
4722		struct pf_src_node	*sn;
4723		struct pf_state		*s;
4724		int			killed = 0;
4725
4726		RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
4727			if (PF_MATCHA(psnk->psnk_src.neg,
4728			    &psnk->psnk_src.addr.v.a.addr,
4729			    &psnk->psnk_src.addr.v.a.mask,
4730			    &sn->addr, sn->af) &&
4731			    PF_MATCHA(psnk->psnk_dst.neg,
4732			    &psnk->psnk_dst.addr.v.a.addr,
4733			    &psnk->psnk_dst.addr.v.a.mask,
4734			    &sn->raddr, sn->af)) {
4735				/* Handle state to src_node linkage */
4736				if (sn->states != 0) {
4737					RB_FOREACH(s, pf_state_tree_id,
4738					    &tree_id) {
4739						if (s->src_node == sn)
4740							s->src_node = NULL;
4741						if (s->nat_src_node == sn)
4742							s->nat_src_node = NULL;
4743					}
4744					sn->states = 0;
4745				}
4746				sn->expire = 1;
4747				killed++;
4748			}
4749		}
4750
4751		if (killed > 0)
4752			pf_purge_expired_src_nodes();
4753
4754		psnk->psnk_af = killed;
4755		break;
4756	}
4757
4758	default:
4759		VERIFY(0);
4760		/* NOTREACHED */
4761	}
4762
4763	return (error);
4764}
4765
4766static int
4767pfioctl_ioc_iface(u_long cmd, struct pfioc_iface_32 *io32,
4768    struct pfioc_iface_64 *io64, struct proc *p)
4769{
4770	int p64 = proc_is64bit(p);
4771	int error = 0;
4772
4773	switch (cmd) {
4774	case DIOCIGETIFACES: {
4775		user_addr_t buf;
4776		int esize;
4777
4778		buf = (p64 ? io64->pfiio_buffer : io32->pfiio_buffer);
4779		esize = (p64 ? io64->pfiio_esize : io32->pfiio_esize);
4780
4781		/* esize must be that of the user space version of pfi_kif */
4782		if (esize != sizeof (struct pfi_uif)) {
4783			error = ENODEV;
4784			break;
4785		}
4786		if (p64)
4787			io64->pfiio_name[sizeof (io64->pfiio_name) - 1] = '\0';
4788		else
4789			io32->pfiio_name[sizeof (io32->pfiio_name) - 1] = '\0';
4790		error = pfi_get_ifaces(
4791		    p64 ? io64->pfiio_name : io32->pfiio_name, buf,
4792		    p64 ? &io64->pfiio_size : &io32->pfiio_size);
4793		break;
4794	}
4795
4796	case DIOCSETIFFLAG: {
4797		if (p64)
4798			io64->pfiio_name[sizeof (io64->pfiio_name) - 1] = '\0';
4799		else
4800			io32->pfiio_name[sizeof (io32->pfiio_name) - 1] = '\0';
4801
4802		error = pfi_set_flags(
4803		    p64 ? io64->pfiio_name : io32->pfiio_name,
4804		    p64 ? io64->pfiio_flags : io32->pfiio_flags);
4805		break;
4806	}
4807
4808	case DIOCCLRIFFLAG: {
4809		if (p64)
4810			io64->pfiio_name[sizeof (io64->pfiio_name) - 1] = '\0';
4811		else
4812			io32->pfiio_name[sizeof (io32->pfiio_name) - 1] = '\0';
4813
4814		error = pfi_clear_flags(
4815		    p64 ? io64->pfiio_name : io32->pfiio_name,
4816		    p64 ? io64->pfiio_flags : io32->pfiio_flags);
4817		break;
4818	}
4819
4820	default:
4821		VERIFY(0);
4822		/* NOTREACHED */
4823	}
4824
4825	return (error);
4826}
4827
4828int
4829pf_af_hook(struct ifnet *ifp, struct mbuf **mppn, struct mbuf **mp,
4830    unsigned int af, int input, struct ip_fw_args *fwa)
4831{
4832	int error = 0;
4833	struct mbuf *nextpkt;
4834	net_thread_marks_t marks;
4835	struct ifnet * pf_ifp = ifp;
4836
4837	marks = net_thread_marks_push(NET_THREAD_HELD_PF);
4838
4839	if (marks != net_thread_marks_none) {
4840		lck_rw_lock_shared(pf_perim_lock);
4841		if (!pf_is_enabled)
4842			goto done;
4843		lck_mtx_lock(pf_lock);
4844	}
4845
4846	if (mppn != NULL && *mppn != NULL)
4847		VERIFY(*mppn == *mp);
4848	if ((nextpkt = (*mp)->m_nextpkt) != NULL)
4849		(*mp)->m_nextpkt = NULL;
4850
4851        /*
4852         * For packets destined to locally hosted IP address
4853         * ip_output_list sets Mbuf's pkt header's rcvif to
4854         * the interface hosting the IP address.
4855         * While on the output path ifp passed to pf_af_hook
4856         * to such local communication is the loopback interface,
4857         * the input path derives ifp from mbuf packet header's
4858         * rcvif.
4859         * This asymmetry caues issues with PF.
4860         * To handle that case, we have a limited change here to
4861         * pass interface as loopback if packets are looped in.
4862         */
4863	if (input && ((*mp)->m_pkthdr.pkt_flags & PKTF_LOOP)) {
4864		pf_ifp = lo_ifp;
4865	}
4866
4867	switch (af) {
4868#if INET
4869	case AF_INET: {
4870		error = pf_inet_hook(pf_ifp, mp, input, fwa);
4871		break;
4872	}
4873#endif /* INET */
4874#if INET6
4875	case AF_INET6:
4876		error = pf_inet6_hook(pf_ifp, mp, input, fwa);
4877		break;
4878#endif /* INET6 */
4879	default:
4880		break;
4881	}
4882
4883	/* When packet valid, link to the next packet */
4884	if (*mp != NULL && nextpkt != NULL) {
4885		struct mbuf *m = *mp;
4886		while (m->m_nextpkt != NULL)
4887			m = m->m_nextpkt;
4888		m->m_nextpkt = nextpkt;
4889	}
4890	/* Fix up linkage of previous packet in the chain */
4891	if (mppn != NULL) {
4892		if (*mp != NULL)
4893			*mppn = *mp;
4894		else
4895			*mppn = nextpkt;
4896	}
4897
4898	if (marks != net_thread_marks_none)
4899		lck_mtx_unlock(pf_lock);
4900
4901done:
4902	if (marks != net_thread_marks_none)
4903		lck_rw_done(pf_perim_lock);
4904
4905	net_thread_marks_pop(marks);
4906	return (error);
4907}
4908
4909
4910#if INET
4911static int
4912pf_inet_hook(struct ifnet *ifp, struct mbuf **mp, int input,
4913    struct ip_fw_args *fwa)
4914{
4915	struct mbuf *m = *mp;
4916#if BYTE_ORDER != BIG_ENDIAN
4917	struct ip *ip = mtod(m, struct ip *);
4918#endif
4919	int error = 0;
4920
4921	/*
4922	 * If the packet is outbound, is originated locally, is flagged for
4923	 * delayed UDP/TCP checksum calculation, and is about to be processed
4924	 * for an interface that doesn't support the appropriate checksum
4925	 * offloading, then calculated the checksum here so that PF can adjust
4926	 * it properly.
4927	 */
4928	if (!input && m->m_pkthdr.rcvif == NULL) {
4929		static const int mask = CSUM_DELAY_DATA;
4930		const int flags = m->m_pkthdr.csum_flags &
4931		    ~IF_HWASSIST_CSUM_FLAGS(ifp->if_hwassist);
4932
4933		if (flags & mask) {
4934			in_delayed_cksum(m);
4935			m->m_pkthdr.csum_flags &= ~mask;
4936		}
4937	}
4938
4939#if BYTE_ORDER != BIG_ENDIAN
4940	HTONS(ip->ip_len);
4941	HTONS(ip->ip_off);
4942#endif
4943	if (pf_test(input ? PF_IN : PF_OUT, ifp, mp, NULL, fwa) != PF_PASS) {
4944		if (*mp != NULL) {
4945			m_freem(*mp);
4946			*mp = NULL;
4947			error = EHOSTUNREACH;
4948		} else {
4949			error = ENOBUFS;
4950		}
4951	}
4952#if BYTE_ORDER != BIG_ENDIAN
4953	else {
4954		if (*mp != NULL) {
4955			ip = mtod(*mp, struct ip *);
4956			NTOHS(ip->ip_len);
4957			NTOHS(ip->ip_off);
4958		}
4959	}
4960#endif
4961	return (error);
4962}
4963#endif /* INET */
4964
4965#if INET6
4966int
4967pf_inet6_hook(struct ifnet *ifp, struct mbuf **mp, int input,
4968    struct ip_fw_args *fwa)
4969{
4970	int error = 0;
4971
4972	/*
4973	 * If the packet is outbound, is originated locally, is flagged for
4974	 * delayed UDP/TCP checksum calculation, and is about to be processed
4975	 * for an interface that doesn't support the appropriate checksum
4976	 * offloading, then calculated the checksum here so that PF can adjust
4977	 * it properly.
4978	 */
4979	if (!input && (*mp)->m_pkthdr.rcvif == NULL) {
4980		static const int mask = CSUM_DELAY_IPV6_DATA;
4981		const int flags = (*mp)->m_pkthdr.csum_flags &
4982		    ~IF_HWASSIST_CSUM_FLAGS(ifp->if_hwassist);
4983
4984		if (flags & mask) {
4985			/*
4986			 * Checksum offload should not have been enabled
4987			 * when extension headers exist, thus 0 for optlen.
4988			 */
4989			in6_delayed_cksum(*mp);
4990			(*mp)->m_pkthdr.csum_flags &= ~mask;
4991		}
4992	}
4993
4994	if (pf_test6(input ? PF_IN : PF_OUT, ifp, mp, NULL, fwa) != PF_PASS) {
4995		if (*mp != NULL) {
4996			m_freem(*mp);
4997			*mp = NULL;
4998			error = EHOSTUNREACH;
4999		} else {
5000			error = ENOBUFS;
5001		}
5002	}
5003	return (error);
5004}
5005#endif /* INET6 */
5006
5007int
5008pf_ifaddr_hook(struct ifnet *ifp)
5009{
5010	struct pfi_kif *kif = ifp->if_pf_kif;
5011
5012	if (kif != NULL) {
5013		lck_rw_lock_shared(pf_perim_lock);
5014		lck_mtx_lock(pf_lock);
5015
5016		pfi_kifaddr_update(kif);
5017
5018		lck_mtx_unlock(pf_lock);
5019		lck_rw_done(pf_perim_lock);
5020	}
5021	return (0);
5022}
5023
5024/*
5025 * Caller acquires dlil lock as writer (exclusive)
5026 */
5027void
5028pf_ifnet_hook(struct ifnet *ifp, int attach)
5029{
5030	lck_rw_lock_shared(pf_perim_lock);
5031	lck_mtx_lock(pf_lock);
5032	if (attach)
5033		pfi_attach_ifnet(ifp);
5034	else
5035		pfi_detach_ifnet(ifp);
5036	lck_mtx_unlock(pf_lock);
5037	lck_rw_done(pf_perim_lock);
5038}
5039
5040static void
5041pf_attach_hooks(void)
5042{
5043	ifnet_head_lock_shared();
5044	/*
5045	 * Check against ifnet_addrs[] before proceeding, in case this
5046	 * is called very early on, e.g. during dlil_init() before any
5047	 * network interface is attached.
5048	 */
5049	if (ifnet_addrs != NULL) {
5050		int i;
5051
5052		for (i = 0; i <= if_index; i++) {
5053			struct ifnet *ifp = ifindex2ifnet[i];
5054			if (ifp != NULL) {
5055				pfi_attach_ifnet(ifp);
5056			}
5057		}
5058	}
5059	ifnet_head_done();
5060}
5061
5062#if 0
5063/* currently unused along with pfdetach() */
5064static void
5065pf_detach_hooks(void)
5066{
5067	ifnet_head_lock_shared();
5068	if (ifnet_addrs != NULL) {
5069		for (i = 0; i <= if_index; i++) {
5070			int i;
5071
5072			struct ifnet *ifp = ifindex2ifnet[i];
5073			if (ifp != NULL && ifp->if_pf_kif != NULL) {
5074				pfi_detach_ifnet(ifp);
5075			}
5076		}
5077	}
5078	ifnet_head_done();
5079}
5080#endif
5081
5082/*
5083 * 'D' group ioctls.
5084 *
5085 * The switch statement below does nothing at runtime, as it serves as a
5086 * compile time check to ensure that all of the socket 'D' ioctls (those
5087 * in the 'D' group going thru soo_ioctl) that are made available by the
5088 * networking stack is unique.  This works as long as this routine gets
5089 * updated each time a new interface ioctl gets added.
5090 *
5091 * Any failures at compile time indicates duplicated ioctl values.
5092 */
5093static __attribute__((unused)) void
5094pfioctl_cassert(void)
5095{
5096	/*
5097	 * This is equivalent to _CASSERT() and the compiler wouldn't
5098	 * generate any instructions, thus for compile time only.
5099	 */
5100	switch ((u_long)0) {
5101	case 0:
5102
5103	/* bsd/net/pfvar.h */
5104	case DIOCSTART:
5105	case DIOCSTOP:
5106	case DIOCADDRULE:
5107	case DIOCGETSTARTERS:
5108	case DIOCGETRULES:
5109	case DIOCGETRULE:
5110	case DIOCSTARTREF:
5111	case DIOCSTOPREF:
5112	case DIOCCLRSTATES:
5113	case DIOCGETSTATE:
5114	case DIOCSETSTATUSIF:
5115	case DIOCGETSTATUS:
5116	case DIOCCLRSTATUS:
5117	case DIOCNATLOOK:
5118	case DIOCSETDEBUG:
5119	case DIOCGETSTATES:
5120	case DIOCCHANGERULE:
5121	case DIOCINSERTRULE:
5122	case DIOCDELETERULE:
5123	case DIOCSETTIMEOUT:
5124	case DIOCGETTIMEOUT:
5125	case DIOCADDSTATE:
5126	case DIOCCLRRULECTRS:
5127	case DIOCGETLIMIT:
5128	case DIOCSETLIMIT:
5129	case DIOCKILLSTATES:
5130	case DIOCSTARTALTQ:
5131	case DIOCSTOPALTQ:
5132	case DIOCADDALTQ:
5133	case DIOCGETALTQS:
5134	case DIOCGETALTQ:
5135	case DIOCCHANGEALTQ:
5136	case DIOCGETQSTATS:
5137	case DIOCBEGINADDRS:
5138	case DIOCADDADDR:
5139	case DIOCGETADDRS:
5140	case DIOCGETADDR:
5141	case DIOCCHANGEADDR:
5142	case DIOCGETRULESETS:
5143	case DIOCGETRULESET:
5144	case DIOCRCLRTABLES:
5145	case DIOCRADDTABLES:
5146	case DIOCRDELTABLES:
5147	case DIOCRGETTABLES:
5148	case DIOCRGETTSTATS:
5149	case DIOCRCLRTSTATS:
5150	case DIOCRCLRADDRS:
5151	case DIOCRADDADDRS:
5152	case DIOCRDELADDRS:
5153	case DIOCRSETADDRS:
5154	case DIOCRGETADDRS:
5155	case DIOCRGETASTATS:
5156	case DIOCRCLRASTATS:
5157	case DIOCRTSTADDRS:
5158	case DIOCRSETTFLAGS:
5159	case DIOCRINADEFINE:
5160	case DIOCOSFPFLUSH:
5161	case DIOCOSFPADD:
5162	case DIOCOSFPGET:
5163	case DIOCXBEGIN:
5164	case DIOCXCOMMIT:
5165	case DIOCXROLLBACK:
5166	case DIOCGETSRCNODES:
5167	case DIOCCLRSRCNODES:
5168	case DIOCSETHOSTID:
5169	case DIOCIGETIFACES:
5170	case DIOCSETIFFLAG:
5171	case DIOCCLRIFFLAG:
5172	case DIOCKILLSRCNODES:
5173	case DIOCGIFSPEED:
5174		;
5175	}
5176}
5177