diff options
author | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2009-03-09 13:53:11 +0000 |
---|---|---|
committer | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2009-03-09 13:53:11 +0000 |
commit | b0a023a94b1bc66e6a579481c636536f1d5d14d7 (patch) | |
tree | 8608b763a542072d4a24af842259dbbaf50c37c7 | |
parent | 3a6e9748f7da78e44e709f4ae46d09b211deb6b6 (diff) |
Make the DIOCSETIFFLAG, DIOCSETLIMIT, and DIOCSETTIMEOUT ioctls
transactional, closing PRs 4941 and 5910. Minor flag day, requires rebuild
of userland tools that use struct pfi_kif.
ok henning deraadt
-rw-r--r-- | sys/net/pf.c | 12 | ||||
-rw-r--r-- | sys/net/pf_if.c | 18 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 54 | ||||
-rw-r--r-- | sys/net/pfvar.h | 5 |
4 files changed, 65 insertions, 24 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index 15a629cd147..0ec86a23189 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.636 2009/03/07 01:15:41 mcbride Exp $ */ +/* $OpenBSD: pf.c,v 1.637 2009/03/09 13:53:09 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -230,11 +230,11 @@ extern struct pool pfr_ktable_pl; extern struct pool pfr_kentry_pl; struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { - { &pf_state_pl, PFSTATE_HIWAT }, - { &pf_src_tree_pl, PFSNODE_HIWAT }, - { &pf_frent_pl, PFFRAG_FRENT_HIWAT }, - { &pfr_ktable_pl, PFR_KTABLE_HIWAT }, - { &pfr_kentry_pl, PFR_KENTRY_HIWAT } + { &pf_state_pl, PFSTATE_HIWAT, PFSTATE_HIWAT }, + { &pf_src_tree_pl, PFSNODE_HIWAT, PFSNODE_HIWAT }, + { &pf_frent_pl, PFFRAG_FRENT_HIWAT, PFFRAG_FRENT_HIWAT }, + { &pfr_ktable_pl, PFR_KTABLE_HIWAT, PFR_KTABLE_HIWAT }, + { &pfr_kentry_pl, PFR_KENTRY_HIWAT, PFR_KENTRY_HIWAT } }; enum { PF_ICMP_MULTI_NONE, PF_ICMP_MULTI_SOLICITED, PF_ICMP_MULTI_LINK }; diff --git a/sys/net/pf_if.c b/sys/net/pf_if.c index ddf5cec4d2f..6a29e361025 100644 --- a/sys/net/pf_if.c +++ b/sys/net/pf_if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_if.c,v 1.55 2008/11/24 13:22:09 mikeb Exp $ */ +/* $OpenBSD: pf_if.c,v 1.56 2009/03/09 13:53:10 mcbride Exp $ */ /* * Copyright 2005 Henning Brauer <henning@openbsd.org> @@ -714,7 +714,7 @@ pfi_set_flags(const char *name, int flags) RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { if (pfi_skip_if(name, p)) continue; - p->pfik_flags |= flags; + p->pfik_flags_new = p->pfik_flags | flags; } splx(s); return (0); @@ -730,12 +730,24 @@ pfi_clear_flags(const char *name, int flags) RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { if (pfi_skip_if(name, p)) continue; - p->pfik_flags &= ~flags; + p->pfik_flags_new = p->pfik_flags & ~flags; } splx(s); return (0); } +void +pfi_xcommit(void) +{ + struct pfi_kif *p; + int s; + + s = splsoftnet(); + RB_FOREACH(p, pfi_ifhead, &pfi_ifs) + p->pfik_flags = p->pfik_flags_new; + splx(s); +} + /* from pf_print_state.c */ int pfi_unmask(void *addr) diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c index c2b0f184984..d59cfe307fa 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.214 2009/02/16 00:31:25 dlg Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.215 2009/03/09 13:53:10 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -114,7 +114,7 @@ int pf_addr_setup(struct pf_ruleset *, struct pf_addr_wrap *, sa_family_t); void pf_addr_copyout(struct pf_addr_wrap *); -struct pf_rule pf_default_rule; +struct pf_rule pf_default_rule, pf_default_rule_new; struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk"); #ifdef ALTQ static int pf_altq_running; @@ -1712,20 +1712,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 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]; if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) pt->seconds = 1; - pf_default_rule.timeout[pt->timeout] = pt->seconds; - if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) - wakeup(pf_purge_thread); - pt->seconds = old; + pf_default_rule_new.timeout[pt->timeout] = pt->seconds; + pt->seconds = pf_default_rule.timeout[pt->timeout]; break; } @@ -1753,21 +1749,19 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) 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) { + if (((struct pool *)pf_pool_limits[pl->index].pp)->pr_nout > + pl->limit) { error = EBUSY; goto fail; } - old_limit = pf_pool_limits[pl->index].limit; - pf_pool_limits[pl->index].limit = pl->limit; - pl->limit = old_limit; + pf_pool_limits[pl->index].limit_new = pl->limit; + pl->limit = pf_pool_limits[pl->index].limit; break; } @@ -2433,6 +2427,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); table = malloc(sizeof(*table), M_TEMP, M_WAITOK); + pf_default_rule_new = pf_default_rule; for (i = 0; i < io->size; i++) { if (copyin(io->array+i, ioe, sizeof(*ioe))) { free(table, M_TEMP); @@ -2619,6 +2614,17 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } } + /* + * Checked already in DIOCSETLIMIT, but check again as the + * situation might have changed. + */ + for (i = 0; i < PF_LIMIT_MAX; i++) { + if (((struct pool *)pf_pool_limits[i].pp)->pr_nout > + pf_pool_limits[i].limit_new) { + error = EBUSY; + goto fail; + } + } /* now do the commit - no errors should happen here */ for (i = 0; i < io->size; i++) { if (copyin(io->array+i, ioe, sizeof(*ioe))) { @@ -2658,6 +2664,26 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } } + for (i = 0; i < PF_LIMIT_MAX; i++) { + if (pf_pool_limits[i].limit_new != + pf_pool_limits[i].limit && + pool_sethardlimit(pf_pool_limits[i].pp, + pf_pool_limits[i].limit_new, NULL, 0) != 0) { + error = EBUSY; + goto fail; /* really bad */ + } + pf_pool_limits[i].limit = pf_pool_limits[i].limit_new; + } + for (i = 0; i < PFTM_MAX; i++) { + int old = pf_default_rule.timeout[i]; + + pf_default_rule.timeout[i] = + pf_default_rule_new.timeout[i]; + if (pf_default_rule.timeout[i] == PFTM_INTERVAL && + pf_default_rule.timeout[i] < old) + wakeup(pf_purge_thread); + } + pfi_xcommit(); free(table, M_TEMP); free(ioe, M_TEMP); break; diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 2de3ff2372b..8dd2f87c0fc 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.283 2009/02/16 00:31:25 dlg Exp $ */ +/* $OpenBSD: pfvar.h,v 1.284 2009/03/09 13:53:10 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -1063,6 +1063,7 @@ struct pfi_kif { u_int64_t pfik_bytes[2][2][2]; u_int32_t pfik_tzero; int pfik_flags; + int pfik_flags_new; void *pfik_ah_cookie; struct ifnet *pfik_ifp; struct ifg_group *pfik_group; @@ -1749,6 +1750,7 @@ void pfi_update_status(const char *, struct pf_status *); int pfi_get_ifaces(const char *, struct pfi_kif *, int *); int pfi_set_flags(const char *, int); int pfi_clear_flags(const char *, int); +void pfi_xcommit(void); int pf_match_tag(struct mbuf *, struct pf_rule *, int *); u_int16_t pf_tagname2tag(char *); @@ -1767,6 +1769,7 @@ extern struct rwlock pf_consistency_lock; struct pf_pool_limit { void *pp; unsigned limit; + unsigned limit_new; }; extern struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX]; |