if (!psk->psk_ifname[0]) pfsync_clear_states(pf_status.hostid);
pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p){	struct pf_pooladdr	*pa = NULL;	struct pf_pool		*pool = NULL;	int			 s;	int			 error = 0;	/* XXX keep in sync with switch() below */	if (securelevel > 1)		switch (cmd) {		case DIOCGETRULES:		case DIOCGETRULE:		case DIOCGETADDRS:		case DIOCGETADDR:		case DIOCGETSTATE:		case DIOCSETSTATUSIF:		case DIOCGETSTATUS:		case DIOCCLRSTATUS:		case DIOCNATLOOK:		case DIOCSETDEBUG:		case DIOCGETSTATES:		case DIOCGETTIMEOUT:		case DIOCCLRRULECTRS:		case DIOCGETLIMIT:		case DIOCGETALTQS:		case DIOCGETALTQ:		case DIOCGETQSTATS:		case DIOCGETANCHORS:		case DIOCGETANCHOR:		case DIOCGETRULESETS:		case DIOCGETRULESET:		case DIOCRGETTABLES:		case DIOCRGETTSTATS:		case DIOCRCLRTSTATS:		case DIOCRCLRADDRS:		case DIOCRADDADDRS:		case DIOCRDELADDRS:		case DIOCRSETADDRS:		case DIOCRGETADDRS:		case DIOCRGETASTATS:		case DIOCRCLRASTATS:		case DIOCRTSTADDRS:		case DIOCOSFPGET:		case DIOCGETSRCNODES:		case DIOCCLRSRCNODES:		case DIOCIGETIFACES:		case DIOCICLRISTATS:			break;		case DIOCRCLRTABLES:		case DIOCRADDTABLES:		case DIOCRDELTABLES:		case DIOCRSETTFLAGS:			if (((struct pfioc_table *)addr)->pfrio_flags &			    PFR_FLAG_DUMMY)				break; /* dummy operation ok */			return (EPERM);		default:			return (EPERM);		}	if (!(flags & FWRITE))		switch (cmd) {		case DIOCGETRULES:		case DIOCGETRULE:		case DIOCGETADDRS:		case DIOCGETADDR:		case DIOCGETSTATE:		case DIOCGETSTATUS:		case DIOCGETSTATES:		case DIOCGETTIMEOUT:		case DIOCGETLIMIT:		case DIOCGETALTQS:		case DIOCGETALTQ:		case DIOCGETQSTATS:		case DIOCGETANCHORS:		case DIOCGETANCHOR:		case DIOCGETRULESETS:		case DIOCGETRULESET:		case DIOCRGETTABLES:		case DIOCRGETTSTATS:		case DIOCRGETADDRS:		case DIOCRGETASTATS:		case DIOCRTSTADDRS:		case DIOCOSFPGET:		case DIOCGETSRCNODES:		case DIOCIGETIFACES:			break;		case DIOCRCLRTABLES:		case DIOCRADDTABLES:		case DIOCRDELTABLES:		case DIOCRCLRTSTATS:		case DIOCRCLRADDRS:		case DIOCRADDADDRS:		case DIOCRDELADDRS:		case DIOCRSETADDRS:		case DIOCRSETTFLAGS:			if (((struct pfioc_table *)addr)->pfrio_flags &			    PFR_FLAG_DUMMY)				break; /* dummy operation ok */			return (EACCES);		default:			return (EACCES);		}	switch (cmd) {	case DIOCSTART:		if (pf_status.running)			error = EEXIST;		else {			pf_status.running = 1;			pf_status.since = time.tv_sec;			DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));		}		break;	case DIOCSTOP:		if (!pf_status.running)			error = ENOENT;		else {			pf_status.running = 0;			pf_status.since = time.tv_sec;			DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));		}		break;	case DIOCBEGINRULES: {		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;		error = pf_begin_rules(&pr->ticket, pf_get_ruleset_number(		    pr->rule.action), pr->anchor, pr->ruleset);		break;	}	case DIOCADDRULE: {		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;		struct pf_ruleset	*ruleset;		struct pf_rule		*rule, *tail;		struct pf_pooladdr	*pa;		int			 rs_num;		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);		if (ruleset == NULL) {			error = EINVAL;			break;		}		rs_num = pf_get_ruleset_number(pr->rule.action);		if (rs_num >= PF_RULESET_MAX) {			error = EINVAL;			break;		}		if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) {			error = EINVAL;			break;		}		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {			error = EINVAL;			break;		}		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {			error = EBUSY;			break;		}		if (pr->pool_ticket != ticket_pabuf) {			error = EBUSY;			break;		}		rule = pool_get(&pf_rule_pl, PR_NOWAIT);		if (rule == NULL) {			error = ENOMEM;			break;		}		bcopy(&pr->rule, rule, sizeof(struct pf_rule));		rule->anchor = NULL;		rule->kif = NULL;		TAILQ_INIT(&rule->rpool.list);		/* initialize refcounting */		rule->states = 0;		rule->src_nodes = 0;		rule->entries.tqe_prev = NULL;#ifndef INET		if (rule->af == AF_INET) {			pool_put(&pf_rule_pl, rule);			error = EAFNOSUPPORT;			break;		}#endif /* INET */#ifndef INET6		if (rule->af == AF_INET6) {			pool_put(&pf_rule_pl, rule);			error = EAFNOSUPPORT;			break;		}#endif /* INET6 */		tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,		    pf_rulequeue);		if (tail)			rule->nr = tail->nr + 1;		else			rule->nr = 0;		if (rule->ifname[0]) {			rule->kif = pfi_attach_rule(rule->ifname);			if (rule->kif == NULL) {				pool_put(&pf_rule_pl, rule);				error = EINVAL;				break;			}		}#ifdef ALTQ		/* set queue IDs */		if (rule->qname[0] != 0) {			if ((rule->qid = pf_qname2qid(rule->qname)) == 0)				error = EBUSY;			else if (rule->pqname[0] != 0) {				if ((rule->pqid =				    pf_qname2qid(rule->pqname)) == 0)					error = EBUSY;			} else				rule->pqid = rule->qid;		}#endif		if (rule->tagname[0])			if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)				error = EBUSY;		if (rule->match_tagname[0])			if ((rule->match_tag =			    pf_tagname2tag(rule->match_tagname)) == 0)				error = EBUSY;		if (rule->rt && !rule->direction)			error = EINVAL;		if (pfi_dynaddr_setup(&rule->src.addr, rule->af))			error = EINVAL;		if (pfi_dynaddr_setup(&rule->dst.addr, rule->af))			error = EINVAL;		if (pf_tbladdr_setup(ruleset, &rule->src.addr))			error = EINVAL;		if (pf_tbladdr_setup(ruleset, &rule->dst.addr))			error = EINVAL;		TAILQ_FOREACH(pa, &pf_pabuf, entries)			if (pf_tbladdr_setup(ruleset, &pa->addr))				error = EINVAL;		pf_mv_pool(&pf_pabuf, &rule->rpool.list);		if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||		    (rule->action == PF_BINAT)) && !rule->anchorname[0]) ||		    (rule->rt > PF_FASTROUTE)) &&		    (TAILQ_FIRST(&rule->rpool.list) == NULL))			error = EINVAL;		if (error) {			pf_rm_rule(NULL, rule);			break;		}		rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);		rule->evaluations = rule->packets = rule->bytes = 0;		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,		    rule, entries);		break;	}	case DIOCCOMMITRULES: {		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;		error = pf_commit_rules(pr->ticket, pf_get_ruleset_number(		    pr->rule.action), pr->anchor, pr->ruleset);		break;	}	case DIOCGETRULES: {		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;		struct pf_ruleset	*ruleset;		struct pf_rule		*tail;		int			 rs_num;		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);		if (ruleset == NULL) {			error = EINVAL;			break;		}		rs_num = pf_get_ruleset_number(pr->rule.action);		if (rs_num >= PF_RULESET_MAX) {			error = EINVAL;			break;		}		s = splsoftnet();		tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,		    pf_rulequeue);		if (tail)			pr->nr = tail->nr + 1;		else			pr->nr = 0;		pr->ticket = ruleset->rules[rs_num].active.ticket;		splx(s);		break;	}	case DIOCGETRULE: {		struct pfioc_rule	*pr = (struct pfioc_rule *)addr;		struct pf_ruleset	*ruleset;		struct pf_rule		*rule;		int			 rs_num, i;		ruleset = pf_find_ruleset(pr->anchor, pr->ruleset);		if (ruleset == NULL) {			error = EINVAL;			break;		}		rs_num = pf_get_ruleset_number(pr->rule.action);		if (rs_num >= PF_RULESET_MAX) {			error = EINVAL;			break;		}		if (pr->ticket != ruleset->rules[rs_num].active.ticket) {			error = EBUSY;			break;		}		s = splsoftnet();		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);		while ((rule != NULL) && (rule->nr != pr->nr))			rule = TAILQ_NEXT(rule, entries);		if (rule == NULL) {			error = EBUSY;			splx(s);			break;		}		bcopy(rule, &pr->rule, sizeof(struct pf_rule));		pfi_dynaddr_copyout(&pr->rule.src.addr);		pfi_dynaddr_copyout(&pr->rule.dst.addr);		pf_tbladdr_copyout(&pr->rule.src.addr);		pf_tbladdr_copyout(&pr->rule.dst.addr);		for (i = 0; i < PF_SKIP_COUNT; ++i)			if (rule->skip[i].ptr == NULL)				pr->rule.skip[i].nr = -1;			else				pr->rule.skip[i].nr =				    rule->skip[i].ptr->nr;		splx(s);		break;	}	case DIOCCHANGERULE: {		struct pfioc_rule	*pcr = (struct pfioc_rule *)addr;		struct pf_ruleset	*ruleset;		struct pf_rule		*oldrule = NULL, *newrule = NULL;		u_int32_t		 nr = 0;		int			 rs_num;		if (!(pcr->action == PF_CHANGE_REMOVE ||		    pcr->action == PF_CHANGE_GET_TICKET) &&		    pcr->pool_ticket != ticket_pabuf) {			error = EBUSY;			break;		}		if (pcr->action < PF_CHANGE_ADD_HEAD ||		    pcr->action > PF_CHANGE_GET_TICKET) {			error = EINVAL;			break;		}		ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset);		if (ruleset == NULL) {			error = EINVAL;			break;		}		rs_num = pf_get_ruleset_number(pcr->rule.action);		if (rs_num >= PF_RULESET_MAX) {			error = EINVAL;			break;		}		if (pcr->action == PF_CHANGE_GET_TICKET) {			pcr->ticket = ++ruleset->rules[rs_num].active.ticket;			break;		} else {			if (pcr->ticket !=			    ruleset->rules[rs_num].active.ticket) {				error = EINVAL;				break;			}			if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {				error = EINVAL;				break;			}		}		if (pcr->action != PF_CHANGE_REMOVE) {			newrule = pool_get(&pf_rule_pl, PR_NOWAIT);			if (newrule == NULL) {				error = ENOMEM;				break;			}			bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));			TAILQ_INIT(&newrule->rpool.list);			/* initialize refcounting */			newrule->states = 0;			newrule->entries.tqe_prev = NULL;#ifndef INET			if (newrule->af == AF_INET) {				pool_put(&pf_rule_pl, newrule);				error = EAFNOSUPPORT;				break;			}#endif /* INET */#ifndef INET6			if (newrule->af == AF_INET6) {				pool_put(&pf_rule_pl, newrule);				error = EAFNOSUPPORT;				break;			}#endif /* INET6 */			if (newrule->ifname[0]) {				newrule->kif = pfi_attach_rule(newrule->ifname);				if (newrule->kif == NULL) {					pool_put(&pf_rule_pl, newrule);					error = EINVAL;					break;				}			} else				newrule->kif = NULL;#ifdef ALTQ			/* set queue IDs */			if (newrule->qname[0] != 0) {				if ((newrule->qid =				    pf_qname2qid(newrule->qname)) == 0)					error = EBUSY;				else if (newrule->pqname[0] != 0) {					if ((newrule->pqid =					    pf_qname2qid(newrule->pqname))  == 0)						error = EBUSY;				} else					newrule->pqid = newrule->qid;			}#endif			if (newrule->tagname[0])				if ((newrule->tag =				    pf_tagname2tag(newrule->tagname)) == 0)					error = EBUSY;			if (newrule->match_tagname[0])				if ((newrule->match_tag = pf_tagname2tag(				    newrule->match_tagname)) == 0)					error = EBUSY;			if (newrule->rt && !newrule->direction)				error = EINVAL;			if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af))				error = EINVAL;			if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af))				error = EINVAL;			if (pf_tbladdr_setup(ruleset, &newrule->src.addr))				error = EINVAL;			if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))				error = EINVAL;			pf_mv_pool(&pf_pabuf, &newrule->rpool.list);			if (((((newrule->action == PF_NAT) ||			    (newrule->action == PF_RDR) ||			    (newrule->action == PF_BINAT) ||			    (newrule->rt > PF_FASTROUTE)) &&			    !newrule->anchorname[0])) &&			    (TAILQ_FIRST(&newrule->rpool.list) == NULL))				error = EINVAL;			if (error) {				pf_rm_rule(NULL, newrule);				break;			}			newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);			newrule->evaluations = newrule->packets = 0;			newrule->bytes = 0;		}		pf_empty_pool(&pf_pabuf);		s = splsoftnet();		if (pcr->action == PF_CHANGE_ADD_HEAD)			oldrule = TAILQ_FIRST(			    ruleset->rules[rs_num].active.ptr);		else if (pcr->action == PF_CHANGE_ADD_TAIL)			oldrule = TAILQ_LAST(			    ruleset->rules[rs_num].active.ptr, pf_rulequeue);		else {			oldrule = TAILQ_FIRST(			    ruleset->rules[rs_num].active.ptr);			while ((oldrule != NULL) && (oldrule->nr != pcr->nr))				oldrule = TAILQ_NEXT(oldrule, entries);			if (oldrule == NULL) {				pf_rm_rule(NULL, newrule);				error = EINVAL;				splx(s);				break;			}		}		if (pcr->action == PF_CHANGE_REMOVE)			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);		else {			if (oldrule == NULL)				TAILQ_INSERT_TAIL(				    ruleset->rules[rs_num].active.ptr,				    newrule, entries);			else if (pcr->action == PF_CHANGE_ADD_HEAD ||			    pcr->action == PF_CHANGE_ADD_BEFORE)				TAILQ_INSERT_BEFORE(oldrule, newrule, entries);			else				TAILQ_INSERT_AFTER(				    ruleset->rules[rs_num].active.ptr,				    oldrule, newrule, entries);		}		nr = 0;		TAILQ_FOREACH(oldrule,		    ruleset->rules[rs_num].active.ptr, entries)			oldrule->nr = nr++;		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);		pf_remove_if_empty_ruleset(ruleset);		pf_update_anchor_rules();		ruleset->rules[rs_num].active.ticket++;		splx(s);		break;	}	case DIOCCLRSTATES: {		struct pf_state		*state;		struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;		int			 killed = 0;		s = splsoftnet();		RB_FOREACH(state, pf_state_tree_id, &tree_id) {			if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,			    state->u.s.kif->pfik_name)) {				state->timeout = PFTM_PURGE;				killed++;			}		}		pf_purge_expired_states();		pf_status.states = 0;		splx(s);		psk->psk_af = killed;#if NPFSYNC		if (!psk->psk_ifname[0])			pfsync_clear_states(pf_status.hostid);#endif		break;	}	case DIOCKILLSTATES: {		struct pf_state		*state;		struct pfioc_state_kill	*psk = (struct pfioc_state_kill *)addr;		int			 killed = 0;		s = splsoftnet();		RB_FOREACH(state, pf_state_tree_id, &tree_id) {			if ((!psk->psk_af || state->af == psk->psk_af)			    && (!psk->psk_proto || psk->psk_proto ==			    state->proto) &&			    PF_MATCHA(psk->psk_src.not,			    &psk->psk_src.addr.v.a.addr,			    &psk->psk_src.addr.v.a.mask,			    &state->lan.addr, state->af) &&			    PF_MATCHA(psk->psk_dst.not,			    &psk->psk_dst.addr.v.a.addr,			    &psk->psk_dst.addr.v.a.mask,			    &state->ext.addr, state->af) &&			    (psk->psk_src.port_op == 0 ||			    pf_match_port(psk->psk_src.port_op,			    psk->psk_src.port[0], psk->psk_src.port[1],			    state->lan.port)) &&			    (psk->psk_dst.port_op == 0 ||			    pf_match_port(psk->psk_dst.port_op,			    psk->psk_dst.port[0], psk->psk_dst.port[1],			    state->ext.port)) &&			    (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,			    state->u.s.kif->pfik_name))) {				state->timeout = PFTM_PURGE;				killed++;			}		}		pf_purge_expired_states();		splx(s);		psk->psk_af = killed;		break;	}	case DIOCADDSTATE: {		struct pfioc_state	*ps = (struct pfioc_state *)addr;		struct pf_state		*state;		struct pfi_kif		*kif;		if (ps->state.timeout >= PFTM_MAX &&		    ps->state.timeout != PFTM_UNTIL_PACKET) {			error = EINVAL;			break;		}		state = pool_get(&pf_state_pl, PR_NOWAIT);		if (state == NULL) {			error = ENOMEM;			break;		}		s = splsoftnet();		kif = pfi_lookup_create(ps->state.u.ifname);		if (kif == NULL) {			error = ENOENT;			splx(s);		}		bcopy(&ps->state, state, sizeof(struct pf_state));		bzero(&state->u, sizeof(state->u));		state->rule.ptr = NULL;		state->nat_rule.ptr = NULL;		state->anchor.ptr = NULL;		state->rt_kif = NULL;		state->creation = time.tv_sec;		state->packets[0] = state->packets[1] = 0;		state->bytes[0] = state->bytes[1] = 0;		if (pf_insert_state(kif, state)) {			pfi_maybe_destroy(kif);			pool_put(&pf_state_pl, state);			error = ENOMEM;		}		splx(s);		break;	}	case DIOCGETSTATE: {		struct pfioc_state	*ps = (struct pfioc_state *)addr;		struct pf_state		*state;		u_int32_t		 nr;		nr = 0;		s = splsoftnet();		RB_FOREACH(state, pf_state_tree_id, &tree_id) {			if (nr >= ps->nr)				break;			nr++;		}		if (state == NULL) {			error = EBUSY;			splx(s);			break;		}		bcopy(state, &ps->state, sizeof(struct pf_state));		ps->state.rule.nr = state->rule.ptr->nr;		ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ?		    -1 : state->nat_rule.ptr->nr;		ps->state.anchor.nr = (state->anchor.ptr == NULL) ?		    -1 : state->anchor.ptr->nr;		splx(s);		ps->state.expire = pf_state_expires(state);		if (ps->state.expire > time.tv_sec)			ps->state.expire -= time.tv_sec;		else			ps->state.expire = 0;		break;	}	case DIOCGETSTATES: {		struct pfioc_states	*ps = (struct pfioc_states *)addr;		struct pf_state		*state;		struct pf_state		*p, pstore;		struct pfi_kif		*kif;		u_int32_t		 nr = 0;		int			 space = ps->ps_len;		if (space == 0) {			s = splsoftnet();			TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states)				nr += kif->pfik_states;			splx(s);			ps->ps_len = sizeof(struct pf_state) * nr;			return (0);		}		s = splsoftnet();		p = ps->ps_states;		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states)			RB_FOREACH(state, pf_state_tree_ext_gwy,			    &kif->pfik_ext_gwy) {				int	secs = time.tv_sec;				if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len)					break;				bcopy(state, &pstore, sizeof(pstore));				strlcpy(pstore.u.ifname, kif->pfik_name,				    sizeof(pstore.u.ifname));				pstore.rule.nr = state->rule.ptr->nr;				pstore.nat_rule.nr = (state->nat_rule.ptr ==				    NULL) ? -1 : state->nat_rule.ptr->nr;				pstore.anchor.nr = (state->anchor.ptr ==				    NULL) ? -1 : state->anchor.ptr->nr;				pstore.creation = secs - pstore.creation;				pstore.expire = pf_state_expires(state);				if (pstore.expire > secs)					pstore.expire -= secs;				else					pstore.expire = 0;				error = copyout(&pstore, p, sizeof(*p));				if (error) {					splx(s);					goto fail;				}				p++;				nr++;			}		ps->ps_len = sizeof(struct pf_state) * nr;		splx(s);		break;	}	case DIOCGETSTATUS: {		struct pf_status *s = (struct pf_status *)addr;		bcopy(&pf_status, s, sizeof(struct pf_status));		pfi_fill_oldstatus(s);		break;	}	case DIOCSETSTATUSIF: {		struct pfioc_if	*pi = (struct pfioc_if *)addr;		if (pi->ifname[0] == 0) {			bzero(pf_status.ifname, IFNAMSIZ);			break;		}		if (ifunit(pi->ifname) == NULL) {			error = EINVAL;			break;		}		strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ);		break;	}	case DIOCCLRSTATUS: {		bzero(pf_status.counters, sizeof(pf_status.counters));		bzero(pf_status.fcounters, sizeof(pf_status.fcounters));		bzero(pf_status.scounters, sizeof(pf_status.scounters));		if (*pf_status.ifname)			pfi_clr_istats(pf_status.ifname, NULL,			    PFI_FLAG_INSTANCE);		break;	}	case DIOCNATLOOK: {		struct pfioc_natlook	*pnl = (struct pfioc_natlook *)addr;		struct pf_state		*state;		struct pf_state		 key;		int			 m = 0, direction = pnl->direction;		key.af = pnl->af;		key.proto = pnl->proto;		if (!pnl->proto ||		    PF_AZERO(&pnl->saddr, pnl->af) ||		    PF_AZERO(&pnl->daddr, pnl->af) ||		    !pnl->dport || !pnl->sport)			error = EINVAL;		else {			s = splsoftnet();			/*			 * userland gives us source and dest of connection,			 * reverse the lookup so we ask for what happens with			 * the return traffic, enabling us to find it in the			 * state tree.			 */			if (direction == PF_IN) {				PF_ACPY(&key.ext.addr, &pnl->daddr, pnl->af);				key.ext.port = pnl->dport;				PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af);				key.gwy.port = pnl->sport;				state = pf_find_state_all(&key, PF_EXT_GWY, &m);			} else {				PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af);				key.lan.port = pnl->dport;				PF_ACPY(&key.ext.addr, &pnl->saddr, pnl->af);				key.ext.port = pnl->sport;				state = pf_find_state_all(&key, PF_LAN_EXT, &m);			}			if (m > 1)				error = E2BIG;	/* more than one state */			else if (state != NULL) {				if (direction == PF_IN) {					PF_ACPY(&pnl->rsaddr, &state->lan.addr,					    state->af);					pnl->rsport = state->lan.port;					PF_ACPY(&pnl->rdaddr, &pnl->daddr,					    pnl->af);					pnl->rdport = pnl->dport;				} else {					PF_ACPY(&pnl->rdaddr, &state->gwy.addr,					    state->af);					pnl->rdport = state->gwy.port;					PF_ACPY(&pnl->rsaddr, &pnl->saddr,					    pnl->af);					pnl->rsport = pnl->sport;				}			} else				error = ENOENT;			splx(s);		}		break;	}	case DIOCSETTIMEOUT: {		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;		int		 old;		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||		    pt->seconds < 0) {			error = EINVAL;			goto fail;		}		old = pf_default_rule.timeout[pt->timeout];		pf_default_rule.timeout[pt->timeout] = pt->seconds;		pt->seconds = old;		break;	}	case DIOCGETTIMEOUT: {		struct pfioc_tm	*pt = (struct pfioc_tm *)addr;		if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {			error = EINVAL;			goto fail;		}		pt->seconds = pf_default_rule.timeout[pt->timeout];		break;	}	case DIOCGETLIMIT: {		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {			error = EINVAL;			goto fail;		}		pl->limit = pf_pool_limits[pl->index].limit;		break;	}	case DIOCSETLIMIT: {		struct pfioc_limit	*pl = (struct pfioc_limit *)addr;		int			 old_limit;		if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||		    pf_pool_limits[pl->index].pp == NULL) {			error = EINVAL;			goto fail;		}		if (pool_sethardlimit(pf_pool_limits[pl->index].pp,		    pl->limit, NULL, 0) != 0) {			error = EBUSY;			goto fail;		}		old_limit = pf_pool_limits[pl->index].limit;		pf_pool_limits[pl->index].limit = pl->limit;		pl->limit = old_limit;		break;	}	case DIOCSETDEBUG: {		u_int32_t	*level = (u_int32_t *)addr;		pf_status.debug = *level;		break;	}	case DIOCCLRRULECTRS: {		struct pf_ruleset	*ruleset = &pf_main_ruleset;		struct pf_rule		*rule;		s = splsoftnet();		TAILQ_FOREACH(rule,		    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)			rule->evaluations = rule->packets =			    rule->bytes = 0;		splx(s);		break;	}#ifdef ALTQ	case DIOCSTARTALTQ: {		struct pf_altq		*altq;		struct ifnet		*ifp;		struct tb_profile	 tb;		/* enable all altq interfaces on active list */		s = splsoftnet();		TAILQ_FOREACH(altq, pf_altqs_active, entries) {			if (altq->qname[0] == 0) {				if ((ifp = ifunit(altq->ifname)) == NULL) {					error = EINVAL;					break;				}				if (ifp->if_snd.altq_type != ALTQT_NONE)					error = altq_enable(&ifp->if_snd);				if (error != 0)					break;				/* set tokenbucket regulator */				tb.rate = altq->ifbandwidth;				tb.depth = altq->tbrsize;				error = tbr_set(&ifp->if_snd, &tb);				if (error != 0)					break;			}		}		if (error == 0)			pfaltq_running = 1;		splx(s);		DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));		break;	}	case DIOCSTOPALTQ: {		struct pf_altq		*altq;		struct ifnet		*ifp;		struct tb_profile	 tb;		int			 err;		/* disable all altq interfaces on active list */		s = splsoftnet();		TAILQ_FOREACH(altq, pf_altqs_active, entries) {			if (altq->qname[0] == 0) {				if ((ifp = ifunit(altq->ifname)) == NULL) {					error = EINVAL;					break;				}				if (ifp->if_snd.altq_type != ALTQT_NONE) {					err = altq_disable(&ifp->if_snd);					if (err != 0 && error == 0)						error = err;				}				/* clear tokenbucket regulator */				tb.rate = 0;				err = tbr_set(&ifp->if_snd, &tb);				if (err != 0 && error == 0)					error = err;			}		}		if (error == 0)			pfaltq_running = 0;		splx(s);		DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));		break;	}	case DIOCBEGINALTQS: {		u_int32_t	*ticket = (u_int32_t *)addr;		error = pf_begin_altq(ticket);		break;	}	case DIOCADDALTQ: {		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;		struct pf_altq		*altq, *a;		if (pa->ticket != ticket_altqs_inactive) {			error = EBUSY;			break;		}		altq = pool_get(&pf_altq_pl, PR_NOWAIT);		if (altq == NULL) {			error = ENOMEM;			break;		}		bcopy(&pa->altq, altq, sizeof(struct pf_altq));		/*		 * if this is for a queue, find the discipline and		 * copy the necessary fields		 */		if (altq->qname[0] != 0) {			if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {				error = EBUSY;				pool_put(&pf_altq_pl, altq);				break;			}			TAILQ_FOREACH(a, pf_altqs_inactive, entries) {				if (strncmp(a->ifname, altq->ifname,				    IFNAMSIZ) == 0 && a->qname[0] == 0) {					altq->altq_disc = a->altq_disc;					break;				}			}		}		error = altq_add(altq);		if (error) {			pool_put(&pf_altq_pl, altq);			break;		}		TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);		bcopy(altq, &pa->altq, sizeof(struct pf_altq));		break;	}	case DIOCCOMMITALTQS: {		u_int32_t		ticket = *(u_int32_t *)addr;		error = pf_commit_altq(ticket);		break;	}	case DIOCGETALTQS: {		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;		struct pf_altq		*altq;		pa->nr = 0;		s = splsoftnet();		TAILQ_FOREACH(altq, pf_altqs_active, entries)			pa->nr++;		pa->ticket = ticket_altqs_active;		splx(s);		break;	}	case DIOCGETALTQ: {		struct pfioc_altq	*pa = (struct pfioc_altq *)addr;		struct pf_altq		*altq;		u_int32_t		 nr;		if (pa->ticket != ticket_altqs_active) {			error = EBUSY;			break;		}		nr = 0;		s = splsoftnet();		altq = TAILQ_FIRST(pf_altqs_active);		while ((altq != NULL) && (nr < pa->nr)) {			altq = TAILQ_NEXT(altq, entries);			nr++;		}		if (altq == NULL) {			error = EBUSY;			splx(s);			break;		}		bcopy(altq, &pa->altq, sizeof(struct pf_altq));		splx(s);		break;	}	case DIOCCHANGEALTQ:		/* CHANGEALTQ not supported yet! */		error = ENODEV;		break;	case DIOCGETQSTATS: {		struct pfioc_qstats	*pq = (struct pfioc_qstats *)addr;		struct pf_altq		*altq;		u_int32_t		 nr;		int			 nbytes;		if (pq->ticket != ticket_altqs_active) {			error = EBUSY;			break;		}		nbytes = pq->nbytes;		nr = 0;		s = splsoftnet();		altq = TAILQ_FIRST(pf_altqs_active);		while ((altq != NULL) && (nr < pq->nr)) {			altq = TAILQ_NEXT(altq, entries);			nr++;		}		if (altq == NULL) {			error = EBUSY;			splx(s);			break;		}		error = altq_getqstats(altq, pq->buf, &nbytes);		splx(s);		if (error == 0) {			pq->scheduler = altq->scheduler;			pq->nbytes = nbytes;		}		break;	}#endif /* ALTQ */	case DIOCBEGINADDRS: {		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;		pf_empty_pool(&pf_pabuf);		pp->ticket = ++ticket_pabuf;		break;	}	case DIOCADDADDR: {		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;#ifndef INET		if (pp->af == AF_INET) {			error = EAFNOSUPPORT;			break;		}#endif /* INET */#ifndef INET6		if (pp->af == AF_INET6) {			error = EAFNOSUPPORT;			break;		}#endif /* INET6 */		if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&		    pp->addr.addr.type != PF_ADDR_DYNIFTL &&		    pp->addr.addr.type != PF_ADDR_TABLE) {			error = EINVAL;			break;		}		pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);		if (pa == NULL) {			error = ENOMEM;			break;		}		bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));		if (pa->ifname[0]) {			pa->kif = pfi_attach_rule(pa->ifname);			if (pa->kif == NULL) {				pool_put(&pf_pooladdr_pl, pa);				error = EINVAL;				break;			}		}		if (pfi_dynaddr_setup(&pa->addr, pp->af)) {			pfi_dynaddr_remove(&pa->addr);			pfi_detach_rule(pa->kif);			pool_put(&pf_pooladdr_pl, pa);			error = EINVAL;			break;		}		TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);		break;	}	case DIOCGETADDRS: {		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;		pp->nr = 0;		s = splsoftnet();		pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,		    pp->r_action, pp->r_num, 0, 1, 0);		if (pool == NULL) {			error = EBUSY;			splx(s);			break;		}		TAILQ_FOREACH(pa, &pool->list, entries)			pp->nr++;		splx(s);		break;	}	case DIOCGETADDR: {		struct pfioc_pooladdr	*pp = (struct pfioc_pooladdr *)addr;		u_int32_t		 nr = 0;		s = splsoftnet();		pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket,		    pp->r_action, pp->r_num, 0, 1, 1);		if (pool == NULL) {			error = EBUSY;			splx(s);			break;		}		pa = TAILQ_FIRST(&pool->list);		while ((pa != NULL) && (nr < pp->nr)) {			pa = TAILQ_NEXT(pa, entries);			nr++;		}		if (pa == NULL) {			error = EBUSY;			splx(s);			break;		}		bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));		pfi_dynaddr_copyout(&pp->addr.addr);		pf_tbladdr_copyout(&pp->addr.addr);		splx(s);		break;	}	case DIOCCHANGEADDR: {		struct pfioc_pooladdr	*pca = (struct pfioc_pooladdr *)addr;		struct pf_pooladdr	*oldpa = NULL, *newpa = NULL;		struct pf_ruleset	*ruleset;		if (pca->action < PF_CHANGE_ADD_HEAD ||		    pca->action > PF_CHANGE_REMOVE) {			error = EINVAL;			break;		}		if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&		    pca->addr.addr.type != PF_ADDR_DYNIFTL &&		    pca->addr.addr.type != PF_ADDR_TABLE) {			error = EINVAL;			break;		}		ruleset = pf_find_ruleset(pca->anchor, pca->ruleset);		if (ruleset == NULL) {			error = EBUSY;			break;		}		pool = pf_get_pool(pca->anchor, pca->ruleset, pca->ticket,		    pca->r_action, pca->r_num, pca->r_last, 1, 1);		if (pool == NULL) {			error = EBUSY;			break;		}		if (pca->action != PF_CHANGE_REMOVE) {			newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);			if (newpa == NULL) {				error = ENOMEM;				break;			}			bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));#ifndef INET			if (pca->af == AF_INET) {				pool_put(&pf_pooladdr_pl, newpa);				error = EAFNOSUPPORT;				break;			}#endif /* INET */#ifndef INET6			if (pca->af == AF_INET6) {				pool_put(&pf_pooladdr_pl, newpa);				error = EAFNOSUPPORT;				break;			}#endif /* INET6 */			if (newpa->ifname[0]) {				newpa->kif = pfi_attach_rule(newpa->ifname);				if (newpa->kif == NULL) {					pool_put(&pf_pooladdr_pl, newpa);					error = EINVAL;					break;				}			} else				newpa->kif = NULL;			if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||			    pf_tbladdr_setup(ruleset, &newpa->addr)) {				pfi_dynaddr_remove(&newpa->addr);				pfi_detach_rule(newpa->kif);				pool_put(&pf_pooladdr_pl, newpa);				error = EINVAL;				break;			}		}		s = splsoftnet();		if (pca->action == PF_CHANGE_ADD_HEAD)			oldpa = TAILQ_FIRST(&pool->list);		else if (pca->action == PF_CHANGE_ADD_TAIL)			oldpa = TAILQ_LAST(&pool->list, pf_palist);		else {			int	i = 0;			oldpa = TAILQ_FIRST(&pool->list);			while ((oldpa != NULL) && (i < pca->nr)) {				oldpa = TAILQ_NEXT(oldpa, entries);				i++;			}			if (oldpa == NULL) {				error = EINVAL;				splx(s);				break;			}		}		if (pca->action == PF_CHANGE_REMOVE) {			TAILQ_REMOVE(&pool->list, oldpa, entries);			pfi_dynaddr_remove(&oldpa->addr);			pf_tbladdr_remove(&oldpa->addr);			pfi_detach_rule(oldpa->kif);			pool_put(&pf_pooladdr_pl, oldpa);		} else {			if (oldpa == NULL)				TAILQ_INSERT_TAIL(&pool->list, newpa, entries);			else if (pca->action == PF_CHANGE_ADD_HEAD ||			    pca->action == PF_CHANGE_ADD_BEFORE)				TAILQ_INSERT_BEFORE(oldpa, newpa, entries);			else				TAILQ_INSERT_AFTER(&pool->list, oldpa,				    newpa, entries);		}		pool->cur = TAILQ_FIRST(&pool->list);		PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,		    pca->af);		splx(s);		break;	}	case DIOCGETANCHORS: {		struct pfioc_anchor	*pa = (struct pfioc_anchor *)addr;		struct pf_anchor	*anchor;		pa->nr = 0;		TAILQ_FOREACH(anchor, &pf_anchors, entries)			pa->nr++;		break;	}	case DIOCGETANCHOR: {		struct pfioc_anchor	*pa = (struct pfioc_anchor *)addr;		struct pf_anchor	*anchor;		u_int32_t		 nr = 0;		anchor = TAILQ_FIRST(&pf_anchors);		while (anchor != NULL && nr < pa->nr) {			anchor = TAILQ_NEXT(anchor, entries);			nr++;		}		if (anchor == NULL)			error = EBUSY;		else			bcopy(anchor->name, pa->name, sizeof(pa->name));		break;	}	case DIOCGETRULESETS: {		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;		struct pf_anchor	*anchor;		struct pf_ruleset	*ruleset;		pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0;		if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {			error = EINVAL;			break;		}		pr->nr = 0;		TAILQ_FOREACH(ruleset, &anchor->rulesets, entries)			pr->nr++;		break;	}	case DIOCGETRULESET: {		struct pfioc_ruleset	*pr = (struct pfioc_ruleset *)addr;		struct pf_anchor	*anchor;		struct pf_ruleset	*ruleset;		u_int32_t		 nr = 0;		if ((anchor = pf_find_anchor(pr->anchor)) == NULL) {			error = EINVAL;			break;		}		ruleset = TAILQ_FIRST(&anchor->rulesets);		while (ruleset != NULL && nr < pr->nr) {			ruleset = TAILQ_NEXT(ruleset, entries);			nr++;		}		if (ruleset == NULL)			error = EBUSY;		else			bcopy(ruleset->name, pr->name, sizeof(pr->name));		break;	}	case DIOCRCLRTABLES: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != 0) {			error = ENODEV;			break;		}		error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,		    io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRADDTABLES: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_table)) {			error = ENODEV;			break;		}		error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,		    &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRDELTABLES: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_table)) {			error = ENODEV;			break;		}		error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,		    &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRGETTABLES: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_table)) {			error = ENODEV;			break;		}		error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRGETTSTATS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_tstats)) {			error = ENODEV;			break;		}		error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRCLRTSTATS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_table)) {			error = ENODEV;			break;		}		error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,		    &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRSETTFLAGS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_table)) {			error = ENODEV;			break;		}		error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,		    io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,		    &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRCLRADDRS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != 0) {			error = ENODEV;			break;		}		error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,		    io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRADDADDRS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_addr)) {			error = ENODEV;			break;		}		error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,		    io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags |		    PFR_FLAG_USERIOCTL);		break;	}	case DIOCRDELADDRS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_addr)) {			error = ENODEV;			break;		}		error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,		    io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags |		    PFR_FLAG_USERIOCTL);		break;	}	case DIOCRSETADDRS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_addr)) {			error = ENODEV;			break;		}		error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,		    io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,		    &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |		    PFR_FLAG_USERIOCTL);		break;	}	case DIOCRGETADDRS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_addr)) {			error = ENODEV;			break;		}		error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRGETASTATS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_astats)) {			error = ENODEV;			break;		}		error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,		    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRCLRASTATS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_addr)) {			error = ENODEV;			break;		}		error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,		    io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags |		    PFR_FLAG_USERIOCTL);		break;	}	case DIOCRTSTADDRS: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_addr)) {			error = ENODEV;			break;		}		error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,		    io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags |		    PFR_FLAG_USERIOCTL);		break;	}	case DIOCRINABEGIN: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != 0) {			error = ENODEV;			break;		}		error = pfr_ina_begin(&io->pfrio_table, &io->pfrio_ticket,		    &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCRINACOMMIT: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != 0) {			error = ENODEV;			break;		}		error = pfr_ina_commit(&io->pfrio_table, io->pfrio_ticket,		    &io->pfrio_nadd, &io->pfrio_nchange, io->pfrio_flags |		    PFR_FLAG_USERIOCTL);		break;	}	case DIOCRINADEFINE: {		struct pfioc_table *io = (struct pfioc_table *)addr;		if (io->pfrio_esize != sizeof(struct pfr_addr)) {			error = ENODEV;			break;		}		error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,		    io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,		    io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL);		break;	}	case DIOCOSFPADD: {		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;		s = splsoftnet();		error = pf_osfp_add(io);		splx(s);		break;	}	case DIOCOSFPGET: {		struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;		s = splsoftnet();		error = pf_osfp_get(io);		splx(s);		break;	}	case DIOCXBEGIN: {		struct pfioc_trans	*io = (struct pfioc_trans *)addr;		struct pfioc_trans_e	 ioe;		struct pfr_table	 table;		int			 i;		if (io->esize != sizeof(ioe)) {			error = ENODEV;			goto fail;		}		for (i = 0; i < io->size; i++) {			if (copyin(io->array+i, &ioe, sizeof(ioe))) {				error = EFAULT;				goto fail;			}			switch (ioe.rs_num) {#ifdef ALTQ			case PF_RULESET_ALTQ:				if (ioe.anchor[0] || ioe.ruleset[0]) {					error = EINVAL;					goto fail;				}				if ((error = pf_begin_altq(&ioe.ticket)))					goto fail;				break;#endif /* ALTQ */			case PF_RULESET_TABLE:				bzero(&table, sizeof(table));				strlcpy(table.pfrt_anchor, ioe.anchor,				    sizeof(table.pfrt_anchor));				strlcpy(table.pfrt_ruleset, ioe.ruleset,				    sizeof(table.pfrt_ruleset));				if ((error = pfr_ina_begin(&table,				    &ioe.ticket, NULL, 0)))					goto fail;				break;			default:				if ((error = pf_begin_rules(&ioe.ticket,				    ioe.rs_num, ioe.anchor, ioe.ruleset)))					goto fail;				break;			}			if (copyout(&ioe, io->array+i, sizeof(io->array[i]))) {				error = EFAULT;				goto fail;			}		}		break;	}	case DIOCXROLLBACK: {		struct pfioc_trans	*io = (struct pfioc_trans *)addr;		struct pfioc_trans_e	 ioe;		struct pfr_table	 table;		int			 i;		if (io->esize != sizeof(ioe)) {			error = ENODEV;			goto fail;		}		for (i = 0; i < io->size; i++) {			if (copyin(io->array+i, &ioe, sizeof(ioe))) {				error = EFAULT;				goto fail;			}			switch (ioe.rs_num) {#ifdef ALTQ			case PF_RULESET_ALTQ:				if (ioe.anchor[0] || ioe.ruleset[0]) {					error = EINVAL;					goto fail;				}				if ((error = pf_rollback_altq(ioe.ticket)))					goto fail; /* really bad */				break;#endif /* ALTQ */			case PF_RULESET_TABLE:				bzero(&table, sizeof(table));				strlcpy(table.pfrt_anchor, ioe.anchor,				    sizeof(table.pfrt_anchor));				strlcpy(table.pfrt_ruleset, ioe.ruleset,				    sizeof(table.pfrt_ruleset));				if ((error = pfr_ina_rollback(&table,				    ioe.ticket, NULL, 0)))					goto fail; /* really bad */				break;			default:				if ((error = pf_rollback_rules(ioe.ticket,				    ioe.rs_num, ioe.anchor, ioe.ruleset)))					goto fail; /* really bad */				break;			}		}		break;	}	case DIOCXCOMMIT: {		struct pfioc_trans	*io = (struct pfioc_trans *)addr;		struct pfioc_trans_e	 ioe;		struct pfr_table	 table;		struct pf_ruleset	*rs;		int			 i;		if (io->esize != sizeof(ioe)) {			error = ENODEV;			goto fail;		}		/* first makes sure everything will succeed */		for (i = 0; i < io->size; i++) {			if (copyin(io->array+i, &ioe, sizeof(ioe))) {				error = EFAULT;				goto fail;			}			switch (ioe.rs_num) {#ifdef ALTQ			case PF_RULESET_ALTQ:				if (ioe.anchor[0] || ioe.ruleset[0]) {					error = EINVAL;					goto fail;				}				if (!altqs_inactive_open || ioe.ticket !=				    ticket_altqs_inactive) {					error = EBUSY;					goto fail;				}				break;#endif /* ALTQ */			case PF_RULESET_TABLE:				rs = pf_find_ruleset(ioe.anchor, ioe.ruleset);				if (rs == NULL || !rs->topen || ioe.ticket !=				     rs->tticket) {					error = EBUSY;					goto fail;				}				break;			default:				if (ioe.rs_num < 0 || ioe.rs_num >=				    PF_RULESET_MAX) {					error = EINVAL;					goto fail;				}				rs = pf_find_ruleset(ioe.anchor, ioe.ruleset);				if (rs == NULL ||				    !rs->rules[ioe.rs_num].inactive.open ||				    rs->rules[ioe.rs_num].inactive.ticket !=				    ioe.ticket) {					error = EBUSY;					goto fail;				}				break;			}		}		/* now do the commit - no errors should happen here */		for (i = 0; i < io->size; i++) {			if (copyin(io->array+i, &ioe, sizeof(ioe))) {				error = EFAULT;				goto fail;			}			switch (ioe.rs_num) {#ifdef ALTQ			case PF_RULESET_ALTQ:				if ((error = pf_commit_altq(ioe.ticket)))					goto fail; /* really bad */				break;#endif /* ALTQ */			case PF_RULESET_TABLE:				bzero(&table, sizeof(table));				strlcpy(table.pfrt_anchor, ioe.anchor,				    sizeof(table.pfrt_anchor));				strlcpy(table.pfrt_ruleset, ioe.ruleset,				    sizeof(table.pfrt_ruleset));				if ((error = pfr_ina_commit(&table, ioe.ticket,				    NULL, NULL, 0)))					goto fail; /* really bad */				break;			default:				if ((error = pf_commit_rules(ioe.ticket,				    ioe.rs_num, ioe.anchor, ioe.ruleset)))					goto fail; /* really bad */				break;			}		}		break;	}	case DIOCGETSRCNODES: {		struct pfioc_src_nodes	*psn = (struct pfioc_src_nodes *)addr;		struct pf_src_node	*n;		struct pf_src_node *p, pstore;		u_int32_t		 nr = 0;		int			 space = psn->psn_len;		if (space == 0) {			s = splsoftnet();			RB_FOREACH(n, pf_src_tree, &tree_src_tracking)				nr++;			splx(s);			psn->psn_len = sizeof(struct pf_src_node) * nr;			return (0);		}		s = splsoftnet();		p = psn->psn_src_nodes;		RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {			int	secs = time.tv_sec;			if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)				break;			bcopy(n, &pstore, sizeof(pstore));			if (n->rule.ptr != NULL)				pstore.rule.nr = n->rule.ptr->nr;			pstore.creation = secs - pstore.creation;			if (pstore.expire > secs)				pstore.expire -= secs;			else				pstore.expire = 0;			error = copyout(&pstore, p, sizeof(*p));			if (error) {				splx(s);				goto fail;			}			p++;			nr++;		}		psn->psn_len = sizeof(struct pf_src_node) * nr;		splx(s);		break;	}	case DIOCCLRSRCNODES: {		struct pf_src_node	*n;		struct pf_state		*state;		s = splsoftnet();		RB_FOREACH(state, pf_state_tree_id, &tree_id) {			state->src_node = NULL;			state->nat_src_node = NULL;		}		RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {			n->expire = 1;			n->states = 0;		}		pf_purge_expired_src_nodes();		pf_status.src_nodes = 0;		splx(s);		break;	}	case DIOCSETHOSTID: {		u_int32_t	*hostid = (u_int32_t *)addr;		if (*hostid == 0) {			error = EINVAL;			goto fail;		}		pf_status.hostid = *hostid;		break;	}	case DIOCOSFPFLUSH:		s = splsoftnet();		pf_osfp_flush();		splx(s);		break;	case DIOCIGETIFACES: {		struct pfioc_iface *io = (struct pfioc_iface *)addr;		if (io->pfiio_esize != sizeof(struct pfi_if)) {			error = ENODEV;			break;		}		error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer,		    &io->pfiio_size, io->pfiio_flags);		break;	}	case DIOCICLRISTATS: {		struct pfioc_iface *io = (struct pfioc_iface *)addr;		error = pfi_clr_istats(io->pfiio_name, &io->pfiio_nzero,		    io->pfiio_flags);		break;	}	default:		error = ENODEV;		break;	}fail:	return (error);}