[BACK]Return to pf_ioctl.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/pf_ioctl.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pf_ioctl.c,v 1.182 2007/06/24 11:17:13 mcbride Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2001 Daniel Hartmeier
        !             5:  * Copyright (c) 2002,2003 Henning Brauer
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  *
        !            12:  *    - Redistributions of source code must retain the above copyright
        !            13:  *      notice, this list of conditions and the following disclaimer.
        !            14:  *    - Redistributions in binary form must reproduce the above
        !            15:  *      copyright notice, this list of conditions and the following
        !            16:  *      disclaimer in the documentation and/or other materials provided
        !            17:  *      with the distribution.
        !            18:  *
        !            19:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
        !            20:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
        !            21:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
        !            22:  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
        !            23:  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            24:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
        !            25:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            26:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
        !            27:  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            29:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            30:  * POSSIBILITY OF SUCH DAMAGE.
        !            31:  *
        !            32:  * Effort sponsored in part by the Defense Advanced Research Projects
        !            33:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
        !            34:  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
        !            35:  *
        !            36:  */
        !            37:
        !            38: #include "pfsync.h"
        !            39:
        !            40: #include <sys/param.h>
        !            41: #include <sys/systm.h>
        !            42: #include <sys/mbuf.h>
        !            43: #include <sys/filio.h>
        !            44: #include <sys/fcntl.h>
        !            45: #include <sys/socket.h>
        !            46: #include <sys/socketvar.h>
        !            47: #include <sys/kernel.h>
        !            48: #include <sys/time.h>
        !            49: #include <sys/timeout.h>
        !            50: #include <sys/pool.h>
        !            51: #include <sys/proc.h>
        !            52: #include <sys/malloc.h>
        !            53: #include <sys/kthread.h>
        !            54: #include <sys/rwlock.h>
        !            55: #include <uvm/uvm_extern.h>
        !            56:
        !            57: #include <net/if.h>
        !            58: #include <net/if_types.h>
        !            59: #include <net/route.h>
        !            60:
        !            61: #include <netinet/in.h>
        !            62: #include <netinet/in_var.h>
        !            63: #include <netinet/in_systm.h>
        !            64: #include <netinet/ip.h>
        !            65: #include <netinet/ip_var.h>
        !            66: #include <netinet/ip_icmp.h>
        !            67:
        !            68: #include <dev/rndvar.h>
        !            69: #include <crypto/md5.h>
        !            70: #include <net/pfvar.h>
        !            71:
        !            72: #if NPFSYNC > 0
        !            73: #include <net/if_pfsync.h>
        !            74: #endif /* NPFSYNC > 0 */
        !            75:
        !            76: #if NPFLOG > 0
        !            77: #include <net/if_pflog.h>
        !            78: #endif /* NPFLOG > 0 */
        !            79:
        !            80: #ifdef INET6
        !            81: #include <netinet/ip6.h>
        !            82: #include <netinet/in_pcb.h>
        !            83: #endif /* INET6 */
        !            84:
        !            85: #ifdef ALTQ
        !            86: #include <altq/altq.h>
        !            87: #endif
        !            88:
        !            89: void                    pfattach(int);
        !            90: void                    pf_thread_create(void *);
        !            91: int                     pfopen(dev_t, int, int, struct proc *);
        !            92: int                     pfclose(dev_t, int, int, struct proc *);
        !            93: struct pf_pool         *pf_get_pool(char *, u_int32_t, u_int8_t, u_int32_t,
        !            94:                            u_int8_t, u_int8_t, u_int8_t);
        !            95:
        !            96: void                    pf_mv_pool(struct pf_palist *, struct pf_palist *);
        !            97: void                    pf_empty_pool(struct pf_palist *);
        !            98: int                     pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
        !            99: #ifdef ALTQ
        !           100: int                     pf_begin_altq(u_int32_t *);
        !           101: int                     pf_rollback_altq(u_int32_t);
        !           102: int                     pf_commit_altq(u_int32_t);
        !           103: int                     pf_enable_altq(struct pf_altq *);
        !           104: int                     pf_disable_altq(struct pf_altq *);
        !           105: #endif /* ALTQ */
        !           106: int                     pf_begin_rules(u_int32_t *, int, const char *);
        !           107: int                     pf_rollback_rules(u_int32_t, int, char *);
        !           108: int                     pf_setup_pfsync_matching(struct pf_ruleset *);
        !           109: void                    pf_hash_rule(MD5_CTX *, struct pf_rule *);
        !           110: void                    pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *);
        !           111: int                     pf_commit_rules(u_int32_t, int, char *);
        !           112: void                    pf_state_export(struct pfsync_state *,
        !           113:                            struct pf_state_key *, struct pf_state *);
        !           114: void                    pf_state_import(struct pfsync_state *,
        !           115:                            struct pf_state_key *, struct pf_state *);
        !           116:
        !           117: struct pf_rule          pf_default_rule;
        !           118: struct rwlock           pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk");
        !           119: #ifdef ALTQ
        !           120: static int              pf_altq_running;
        !           121: #endif
        !           122:
        !           123: #define        TAGID_MAX        50000
        !           124: TAILQ_HEAD(pf_tags, pf_tagname)        pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags),
        !           125:                                pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids);
        !           126:
        !           127: #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
        !           128: #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
        !           129: #endif
        !           130: u_int16_t               tagname2tag(struct pf_tags *, char *);
        !           131: void                    tag2tagname(struct pf_tags *, u_int16_t, char *);
        !           132: void                    tag_unref(struct pf_tags *, u_int16_t);
        !           133: int                     pf_rtlabel_add(struct pf_addr_wrap *);
        !           134: void                    pf_rtlabel_remove(struct pf_addr_wrap *);
        !           135: void                    pf_rtlabel_copyout(struct pf_addr_wrap *);
        !           136:
        !           137: #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
        !           138:
        !           139: void
        !           140: pfattach(int num)
        !           141: {
        !           142:        u_int32_t *timeout = pf_default_rule.timeout;
        !           143:
        !           144:        pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl",
        !           145:            &pool_allocator_nointr);
        !           146:        pool_init(&pf_src_tree_pl, sizeof(struct pf_src_node), 0, 0, 0,
        !           147:            "pfsrctrpl", NULL);
        !           148:        pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl",
        !           149:            NULL);
        !           150:        pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0,
        !           151:            "pfstatekeypl", NULL);
        !           152:        pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl",
        !           153:            &pool_allocator_nointr);
        !           154:        pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
        !           155:            "pfpooladdrpl", &pool_allocator_nointr);
        !           156:        pfr_initialize();
        !           157:        pfi_initialize();
        !           158:        pf_osfp_initialize();
        !           159:
        !           160:        pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp,
        !           161:            pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0);
        !           162:
        !           163:        if (ctob(physmem) <= 100*1024*1024)
        !           164:                pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit =
        !           165:                    PFR_KENTRY_HIWAT_SMALL;
        !           166:
        !           167:        RB_INIT(&tree_src_tracking);
        !           168:        RB_INIT(&pf_anchors);
        !           169:        pf_init_ruleset(&pf_main_ruleset);
        !           170:        TAILQ_INIT(&pf_altqs[0]);
        !           171:        TAILQ_INIT(&pf_altqs[1]);
        !           172:        TAILQ_INIT(&pf_pabuf);
        !           173:        pf_altqs_active = &pf_altqs[0];
        !           174:        pf_altqs_inactive = &pf_altqs[1];
        !           175:        TAILQ_INIT(&state_list);
        !           176:
        !           177:        /* default rule should never be garbage collected */
        !           178:        pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
        !           179:        pf_default_rule.action = PF_PASS;
        !           180:        pf_default_rule.nr = -1;
        !           181:        pf_default_rule.rtableid = -1;
        !           182:
        !           183:        /* initialize default timeouts */
        !           184:        timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
        !           185:        timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
        !           186:        timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
        !           187:        timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
        !           188:        timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
        !           189:        timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
        !           190:        timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
        !           191:        timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
        !           192:        timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
        !           193:        timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
        !           194:        timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
        !           195:        timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
        !           196:        timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
        !           197:        timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
        !           198:        timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
        !           199:        timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
        !           200:        timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
        !           201:        timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
        !           202:        timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
        !           203:        timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
        !           204:
        !           205:        pf_normalize_init();
        !           206:        bzero(&pf_status, sizeof(pf_status));
        !           207:        pf_status.debug = PF_DEBUG_URGENT;
        !           208:
        !           209:        /* XXX do our best to avoid a conflict */
        !           210:        pf_status.hostid = arc4random();
        !           211:
        !           212:        /* require process context to purge states, so perform in a thread */
        !           213:        kthread_create_deferred(pf_thread_create, NULL);
        !           214: }
        !           215:
        !           216: void
        !           217: pf_thread_create(void *v)
        !           218: {
        !           219:        if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge"))
        !           220:                panic("pfpurge thread");
        !           221: }
        !           222:
        !           223: int
        !           224: pfopen(dev_t dev, int flags, int fmt, struct proc *p)
        !           225: {
        !           226:        if (minor(dev) >= 1)
        !           227:                return (ENXIO);
        !           228:        return (0);
        !           229: }
        !           230:
        !           231: int
        !           232: pfclose(dev_t dev, int flags, int fmt, struct proc *p)
        !           233: {
        !           234:        if (minor(dev) >= 1)
        !           235:                return (ENXIO);
        !           236:        return (0);
        !           237: }
        !           238:
        !           239: struct pf_pool *
        !           240: pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action,
        !           241:     u_int32_t rule_number, u_int8_t r_last, u_int8_t active,
        !           242:     u_int8_t check_ticket)
        !           243: {
        !           244:        struct pf_ruleset       *ruleset;
        !           245:        struct pf_rule          *rule;
        !           246:        int                      rs_num;
        !           247:
        !           248:        ruleset = pf_find_ruleset(anchor);
        !           249:        if (ruleset == NULL)
        !           250:                return (NULL);
        !           251:        rs_num = pf_get_ruleset_number(rule_action);
        !           252:        if (rs_num >= PF_RULESET_MAX)
        !           253:                return (NULL);
        !           254:        if (active) {
        !           255:                if (check_ticket && ticket !=
        !           256:                    ruleset->rules[rs_num].active.ticket)
        !           257:                        return (NULL);
        !           258:                if (r_last)
        !           259:                        rule = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
        !           260:                            pf_rulequeue);
        !           261:                else
        !           262:                        rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
        !           263:        } else {
        !           264:                if (check_ticket && ticket !=
        !           265:                    ruleset->rules[rs_num].inactive.ticket)
        !           266:                        return (NULL);
        !           267:                if (r_last)
        !           268:                        rule = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
        !           269:                            pf_rulequeue);
        !           270:                else
        !           271:                        rule = TAILQ_FIRST(ruleset->rules[rs_num].inactive.ptr);
        !           272:        }
        !           273:        if (!r_last) {
        !           274:                while ((rule != NULL) && (rule->nr != rule_number))
        !           275:                        rule = TAILQ_NEXT(rule, entries);
        !           276:        }
        !           277:        if (rule == NULL)
        !           278:                return (NULL);
        !           279:
        !           280:        return (&rule->rpool);
        !           281: }
        !           282:
        !           283: void
        !           284: pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb)
        !           285: {
        !           286:        struct pf_pooladdr      *mv_pool_pa;
        !           287:
        !           288:        while ((mv_pool_pa = TAILQ_FIRST(poola)) != NULL) {
        !           289:                TAILQ_REMOVE(poola, mv_pool_pa, entries);
        !           290:                TAILQ_INSERT_TAIL(poolb, mv_pool_pa, entries);
        !           291:        }
        !           292: }
        !           293:
        !           294: void
        !           295: pf_empty_pool(struct pf_palist *poola)
        !           296: {
        !           297:        struct pf_pooladdr      *empty_pool_pa;
        !           298:
        !           299:        while ((empty_pool_pa = TAILQ_FIRST(poola)) != NULL) {
        !           300:                pfi_dynaddr_remove(&empty_pool_pa->addr);
        !           301:                pf_tbladdr_remove(&empty_pool_pa->addr);
        !           302:                pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE);
        !           303:                TAILQ_REMOVE(poola, empty_pool_pa, entries);
        !           304:                pool_put(&pf_pooladdr_pl, empty_pool_pa);
        !           305:        }
        !           306: }
        !           307:
        !           308: void
        !           309: pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
        !           310: {
        !           311:        if (rulequeue != NULL) {
        !           312:                if (rule->states <= 0) {
        !           313:                        /*
        !           314:                         * XXX - we need to remove the table *before* detaching
        !           315:                         * the rule to make sure the table code does not delete
        !           316:                         * the anchor under our feet.
        !           317:                         */
        !           318:                        pf_tbladdr_remove(&rule->src.addr);
        !           319:                        pf_tbladdr_remove(&rule->dst.addr);
        !           320:                        if (rule->overload_tbl)
        !           321:                                pfr_detach_table(rule->overload_tbl);
        !           322:                }
        !           323:                TAILQ_REMOVE(rulequeue, rule, entries);
        !           324:                rule->entries.tqe_prev = NULL;
        !           325:                rule->nr = -1;
        !           326:        }
        !           327:
        !           328:        if (rule->states > 0 || rule->src_nodes > 0 ||
        !           329:            rule->entries.tqe_prev != NULL)
        !           330:                return;
        !           331:        pf_tag_unref(rule->tag);
        !           332:        pf_tag_unref(rule->match_tag);
        !           333: #ifdef ALTQ
        !           334:        if (rule->pqid != rule->qid)
        !           335:                pf_qid_unref(rule->pqid);
        !           336:        pf_qid_unref(rule->qid);
        !           337: #endif
        !           338:        pf_rtlabel_remove(&rule->src.addr);
        !           339:        pf_rtlabel_remove(&rule->dst.addr);
        !           340:        pfi_dynaddr_remove(&rule->src.addr);
        !           341:        pfi_dynaddr_remove(&rule->dst.addr);
        !           342:        if (rulequeue == NULL) {
        !           343:                pf_tbladdr_remove(&rule->src.addr);
        !           344:                pf_tbladdr_remove(&rule->dst.addr);
        !           345:                if (rule->overload_tbl)
        !           346:                        pfr_detach_table(rule->overload_tbl);
        !           347:        }
        !           348:        pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
        !           349:        pf_anchor_remove(rule);
        !           350:        pf_empty_pool(&rule->rpool.list);
        !           351:        pool_put(&pf_rule_pl, rule);
        !           352: }
        !           353:
        !           354: u_int16_t
        !           355: tagname2tag(struct pf_tags *head, char *tagname)
        !           356: {
        !           357:        struct pf_tagname       *tag, *p = NULL;
        !           358:        u_int16_t                new_tagid = 1;
        !           359:
        !           360:        TAILQ_FOREACH(tag, head, entries)
        !           361:                if (strcmp(tagname, tag->name) == 0) {
        !           362:                        tag->ref++;
        !           363:                        return (tag->tag);
        !           364:                }
        !           365:
        !           366:        /*
        !           367:         * to avoid fragmentation, we do a linear search from the beginning
        !           368:         * and take the first free slot we find. if there is none or the list
        !           369:         * is empty, append a new entry at the end.
        !           370:         */
        !           371:
        !           372:        /* new entry */
        !           373:        if (!TAILQ_EMPTY(head))
        !           374:                for (p = TAILQ_FIRST(head); p != NULL &&
        !           375:                    p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
        !           376:                        new_tagid = p->tag + 1;
        !           377:
        !           378:        if (new_tagid > TAGID_MAX)
        !           379:                return (0);
        !           380:
        !           381:        /* allocate and fill new struct pf_tagname */
        !           382:        tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname),
        !           383:            M_TEMP, M_NOWAIT);
        !           384:        if (tag == NULL)
        !           385:                return (0);
        !           386:        bzero(tag, sizeof(struct pf_tagname));
        !           387:        strlcpy(tag->name, tagname, sizeof(tag->name));
        !           388:        tag->tag = new_tagid;
        !           389:        tag->ref++;
        !           390:
        !           391:        if (p != NULL)  /* insert new entry before p */
        !           392:                TAILQ_INSERT_BEFORE(p, tag, entries);
        !           393:        else    /* either list empty or no free slot in between */
        !           394:                TAILQ_INSERT_TAIL(head, tag, entries);
        !           395:
        !           396:        return (tag->tag);
        !           397: }
        !           398:
        !           399: void
        !           400: tag2tagname(struct pf_tags *head, u_int16_t tagid, char *p)
        !           401: {
        !           402:        struct pf_tagname       *tag;
        !           403:
        !           404:        TAILQ_FOREACH(tag, head, entries)
        !           405:                if (tag->tag == tagid) {
        !           406:                        strlcpy(p, tag->name, PF_TAG_NAME_SIZE);
        !           407:                        return;
        !           408:                }
        !           409: }
        !           410:
        !           411: void
        !           412: tag_unref(struct pf_tags *head, u_int16_t tag)
        !           413: {
        !           414:        struct pf_tagname       *p, *next;
        !           415:
        !           416:        if (tag == 0)
        !           417:                return;
        !           418:
        !           419:        for (p = TAILQ_FIRST(head); p != NULL; p = next) {
        !           420:                next = TAILQ_NEXT(p, entries);
        !           421:                if (tag == p->tag) {
        !           422:                        if (--p->ref == 0) {
        !           423:                                TAILQ_REMOVE(head, p, entries);
        !           424:                                free(p, M_TEMP);
        !           425:                        }
        !           426:                        break;
        !           427:                }
        !           428:        }
        !           429: }
        !           430:
        !           431: u_int16_t
        !           432: pf_tagname2tag(char *tagname)
        !           433: {
        !           434:        return (tagname2tag(&pf_tags, tagname));
        !           435: }
        !           436:
        !           437: void
        !           438: pf_tag2tagname(u_int16_t tagid, char *p)
        !           439: {
        !           440:        tag2tagname(&pf_tags, tagid, p);
        !           441: }
        !           442:
        !           443: void
        !           444: pf_tag_ref(u_int16_t tag)
        !           445: {
        !           446:        struct pf_tagname *t;
        !           447:
        !           448:        TAILQ_FOREACH(t, &pf_tags, entries)
        !           449:                if (t->tag == tag)
        !           450:                        break;
        !           451:        if (t != NULL)
        !           452:                t->ref++;
        !           453: }
        !           454:
        !           455: void
        !           456: pf_tag_unref(u_int16_t tag)
        !           457: {
        !           458:        tag_unref(&pf_tags, tag);
        !           459: }
        !           460:
        !           461: int
        !           462: pf_rtlabel_add(struct pf_addr_wrap *a)
        !           463: {
        !           464:        if (a->type == PF_ADDR_RTLABEL &&
        !           465:            (a->v.rtlabel = rtlabel_name2id(a->v.rtlabelname)) == 0)
        !           466:                return (-1);
        !           467:        return (0);
        !           468: }
        !           469:
        !           470: void
        !           471: pf_rtlabel_remove(struct pf_addr_wrap *a)
        !           472: {
        !           473:        if (a->type == PF_ADDR_RTLABEL)
        !           474:                rtlabel_unref(a->v.rtlabel);
        !           475: }
        !           476:
        !           477: void
        !           478: pf_rtlabel_copyout(struct pf_addr_wrap *a)
        !           479: {
        !           480:        const char      *name;
        !           481:
        !           482:        if (a->type == PF_ADDR_RTLABEL && a->v.rtlabel) {
        !           483:                if ((name = rtlabel_id2name(a->v.rtlabel)) == NULL)
        !           484:                        strlcpy(a->v.rtlabelname, "?",
        !           485:                            sizeof(a->v.rtlabelname));
        !           486:                else
        !           487:                        strlcpy(a->v.rtlabelname, name,
        !           488:                            sizeof(a->v.rtlabelname));
        !           489:        }
        !           490: }
        !           491:
        !           492: #ifdef ALTQ
        !           493: u_int32_t
        !           494: pf_qname2qid(char *qname)
        !           495: {
        !           496:        return ((u_int32_t)tagname2tag(&pf_qids, qname));
        !           497: }
        !           498:
        !           499: void
        !           500: pf_qid2qname(u_int32_t qid, char *p)
        !           501: {
        !           502:        tag2tagname(&pf_qids, (u_int16_t)qid, p);
        !           503: }
        !           504:
        !           505: void
        !           506: pf_qid_unref(u_int32_t qid)
        !           507: {
        !           508:        tag_unref(&pf_qids, (u_int16_t)qid);
        !           509: }
        !           510:
        !           511: int
        !           512: pf_begin_altq(u_int32_t *ticket)
        !           513: {
        !           514:        struct pf_altq  *altq;
        !           515:        int              error = 0;
        !           516:
        !           517:        /* Purge the old altq list */
        !           518:        while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
        !           519:                TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
        !           520:                if (altq->qname[0] == 0) {
        !           521:                        /* detach and destroy the discipline */
        !           522:                        error = altq_remove(altq);
        !           523:                } else
        !           524:                        pf_qid_unref(altq->qid);
        !           525:                pool_put(&pf_altq_pl, altq);
        !           526:        }
        !           527:        if (error)
        !           528:                return (error);
        !           529:        *ticket = ++ticket_altqs_inactive;
        !           530:        altqs_inactive_open = 1;
        !           531:        return (0);
        !           532: }
        !           533:
        !           534: int
        !           535: pf_rollback_altq(u_int32_t ticket)
        !           536: {
        !           537:        struct pf_altq  *altq;
        !           538:        int              error = 0;
        !           539:
        !           540:        if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
        !           541:                return (0);
        !           542:        /* Purge the old altq list */
        !           543:        while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
        !           544:                TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
        !           545:                if (altq->qname[0] == 0) {
        !           546:                        /* detach and destroy the discipline */
        !           547:                        error = altq_remove(altq);
        !           548:                } else
        !           549:                        pf_qid_unref(altq->qid);
        !           550:                pool_put(&pf_altq_pl, altq);
        !           551:        }
        !           552:        altqs_inactive_open = 0;
        !           553:        return (error);
        !           554: }
        !           555:
        !           556: int
        !           557: pf_commit_altq(u_int32_t ticket)
        !           558: {
        !           559:        struct pf_altqqueue     *old_altqs;
        !           560:        struct pf_altq          *altq;
        !           561:        int                      s, err, error = 0;
        !           562:
        !           563:        if (!altqs_inactive_open || ticket != ticket_altqs_inactive)
        !           564:                return (EBUSY);
        !           565:
        !           566:        /* swap altqs, keep the old. */
        !           567:        s = splsoftnet();
        !           568:        old_altqs = pf_altqs_active;
        !           569:        pf_altqs_active = pf_altqs_inactive;
        !           570:        pf_altqs_inactive = old_altqs;
        !           571:        ticket_altqs_active = ticket_altqs_inactive;
        !           572:
        !           573:        /* Attach new disciplines */
        !           574:        TAILQ_FOREACH(altq, pf_altqs_active, entries) {
        !           575:                if (altq->qname[0] == 0) {
        !           576:                        /* attach the discipline */
        !           577:                        error = altq_pfattach(altq);
        !           578:                        if (error == 0 && pf_altq_running)
        !           579:                                error = pf_enable_altq(altq);
        !           580:                        if (error != 0) {
        !           581:                                splx(s);
        !           582:                                return (error);
        !           583:                        }
        !           584:                }
        !           585:        }
        !           586:
        !           587:        /* Purge the old altq list */
        !           588:        while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
        !           589:                TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
        !           590:                if (altq->qname[0] == 0) {
        !           591:                        /* detach and destroy the discipline */
        !           592:                        if (pf_altq_running)
        !           593:                                error = pf_disable_altq(altq);
        !           594:                        err = altq_pfdetach(altq);
        !           595:                        if (err != 0 && error == 0)
        !           596:                                error = err;
        !           597:                        err = altq_remove(altq);
        !           598:                        if (err != 0 && error == 0)
        !           599:                                error = err;
        !           600:                } else
        !           601:                        pf_qid_unref(altq->qid);
        !           602:                pool_put(&pf_altq_pl, altq);
        !           603:        }
        !           604:        splx(s);
        !           605:
        !           606:        altqs_inactive_open = 0;
        !           607:        return (error);
        !           608: }
        !           609:
        !           610: int
        !           611: pf_enable_altq(struct pf_altq *altq)
        !           612: {
        !           613:        struct ifnet            *ifp;
        !           614:        struct tb_profile        tb;
        !           615:        int                      s, error = 0;
        !           616:
        !           617:        if ((ifp = ifunit(altq->ifname)) == NULL)
        !           618:                return (EINVAL);
        !           619:
        !           620:        if (ifp->if_snd.altq_type != ALTQT_NONE)
        !           621:                error = altq_enable(&ifp->if_snd);
        !           622:
        !           623:        /* set tokenbucket regulator */
        !           624:        if (error == 0 && ifp != NULL && ALTQ_IS_ENABLED(&ifp->if_snd)) {
        !           625:                tb.rate = altq->ifbandwidth;
        !           626:                tb.depth = altq->tbrsize;
        !           627:                s = splnet();
        !           628:                error = tbr_set(&ifp->if_snd, &tb);
        !           629:                splx(s);
        !           630:        }
        !           631:
        !           632:        return (error);
        !           633: }
        !           634:
        !           635: int
        !           636: pf_disable_altq(struct pf_altq *altq)
        !           637: {
        !           638:        struct ifnet            *ifp;
        !           639:        struct tb_profile        tb;
        !           640:        int                      s, error;
        !           641:
        !           642:        if ((ifp = ifunit(altq->ifname)) == NULL)
        !           643:                return (EINVAL);
        !           644:
        !           645:        /*
        !           646:         * when the discipline is no longer referenced, it was overridden
        !           647:         * by a new one.  if so, just return.
        !           648:         */
        !           649:        if (altq->altq_disc != ifp->if_snd.altq_disc)
        !           650:                return (0);
        !           651:
        !           652:        error = altq_disable(&ifp->if_snd);
        !           653:
        !           654:        if (error == 0) {
        !           655:                /* clear tokenbucket regulator */
        !           656:                tb.rate = 0;
        !           657:                s = splnet();
        !           658:                error = tbr_set(&ifp->if_snd, &tb);
        !           659:                splx(s);
        !           660:        }
        !           661:
        !           662:        return (error);
        !           663: }
        !           664: #endif /* ALTQ */
        !           665:
        !           666: int
        !           667: pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
        !           668: {
        !           669:        struct pf_ruleset       *rs;
        !           670:        struct pf_rule          *rule;
        !           671:
        !           672:        if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
        !           673:                return (EINVAL);
        !           674:        rs = pf_find_or_create_ruleset(anchor);
        !           675:        if (rs == NULL)
        !           676:                return (EINVAL);
        !           677:        while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
        !           678:                pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
        !           679:                rs->rules[rs_num].inactive.rcount--;
        !           680:        }
        !           681:        *ticket = ++rs->rules[rs_num].inactive.ticket;
        !           682:        rs->rules[rs_num].inactive.open = 1;
        !           683:        return (0);
        !           684: }
        !           685:
        !           686: int
        !           687: pf_rollback_rules(u_int32_t ticket, int rs_num, char *anchor)
        !           688: {
        !           689:        struct pf_ruleset       *rs;
        !           690:        struct pf_rule          *rule;
        !           691:
        !           692:        if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
        !           693:                return (EINVAL);
        !           694:        rs = pf_find_ruleset(anchor);
        !           695:        if (rs == NULL || !rs->rules[rs_num].inactive.open ||
        !           696:            rs->rules[rs_num].inactive.ticket != ticket)
        !           697:                return (0);
        !           698:        while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
        !           699:                pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
        !           700:                rs->rules[rs_num].inactive.rcount--;
        !           701:        }
        !           702:        rs->rules[rs_num].inactive.open = 0;
        !           703:        return (0);
        !           704: }
        !           705:
        !           706: #define PF_MD5_UPD(st, elm)                                            \
        !           707:                MD5Update(ctx, (u_int8_t *) &(st)->elm, sizeof((st)->elm))
        !           708:
        !           709: #define PF_MD5_UPD_STR(st, elm)                                                \
        !           710:                MD5Update(ctx, (u_int8_t *) (st)->elm, strlen((st)->elm))
        !           711:
        !           712: #define PF_MD5_UPD_HTONL(st, elm, stor) do {                           \
        !           713:                (stor) = htonl((st)->elm);                              \
        !           714:                MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int32_t));\
        !           715: } while (0)
        !           716:
        !           717: #define PF_MD5_UPD_HTONS(st, elm, stor) do {                           \
        !           718:                (stor) = htons((st)->elm);                              \
        !           719:                MD5Update(ctx, (u_int8_t *) &(stor), sizeof(u_int16_t));\
        !           720: } while (0)
        !           721:
        !           722: void
        !           723: pf_hash_rule_addr(MD5_CTX *ctx, struct pf_rule_addr *pfr)
        !           724: {
        !           725:        PF_MD5_UPD(pfr, addr.type);
        !           726:        switch (pfr->addr.type) {
        !           727:                case PF_ADDR_DYNIFTL:
        !           728:                        PF_MD5_UPD(pfr, addr.v.ifname);
        !           729:                        PF_MD5_UPD(pfr, addr.iflags);
        !           730:                        break;
        !           731:                case PF_ADDR_TABLE:
        !           732:                        PF_MD5_UPD(pfr, addr.v.tblname);
        !           733:                        break;
        !           734:                case PF_ADDR_ADDRMASK:
        !           735:                        /* XXX ignore af? */
        !           736:                        PF_MD5_UPD(pfr, addr.v.a.addr.addr32);
        !           737:                        PF_MD5_UPD(pfr, addr.v.a.mask.addr32);
        !           738:                        break;
        !           739:                case PF_ADDR_RTLABEL:
        !           740:                        PF_MD5_UPD(pfr, addr.v.rtlabelname);
        !           741:                        break;
        !           742:        }
        !           743:
        !           744:        PF_MD5_UPD(pfr, port[0]);
        !           745:        PF_MD5_UPD(pfr, port[1]);
        !           746:        PF_MD5_UPD(pfr, neg);
        !           747:        PF_MD5_UPD(pfr, port_op);
        !           748: }
        !           749:
        !           750: void
        !           751: pf_hash_rule(MD5_CTX *ctx, struct pf_rule *rule)
        !           752: {
        !           753:        u_int16_t x;
        !           754:        u_int32_t y;
        !           755:
        !           756:        pf_hash_rule_addr(ctx, &rule->src);
        !           757:        pf_hash_rule_addr(ctx, &rule->dst);
        !           758:        PF_MD5_UPD_STR(rule, label);
        !           759:        PF_MD5_UPD_STR(rule, ifname);
        !           760:        PF_MD5_UPD_STR(rule, match_tagname);
        !           761:        PF_MD5_UPD_HTONS(rule, match_tag, x); /* dup? */
        !           762:        PF_MD5_UPD_HTONL(rule, os_fingerprint, y);
        !           763:        PF_MD5_UPD_HTONL(rule, prob, y);
        !           764:        PF_MD5_UPD_HTONL(rule, uid.uid[0], y);
        !           765:        PF_MD5_UPD_HTONL(rule, uid.uid[1], y);
        !           766:        PF_MD5_UPD(rule, uid.op);
        !           767:        PF_MD5_UPD_HTONL(rule, gid.gid[0], y);
        !           768:        PF_MD5_UPD_HTONL(rule, gid.gid[1], y);
        !           769:        PF_MD5_UPD(rule, gid.op);
        !           770:        PF_MD5_UPD_HTONL(rule, rule_flag, y);
        !           771:        PF_MD5_UPD(rule, action);
        !           772:        PF_MD5_UPD(rule, direction);
        !           773:        PF_MD5_UPD(rule, af);
        !           774:        PF_MD5_UPD(rule, quick);
        !           775:        PF_MD5_UPD(rule, ifnot);
        !           776:        PF_MD5_UPD(rule, match_tag_not);
        !           777:        PF_MD5_UPD(rule, natpass);
        !           778:        PF_MD5_UPD(rule, keep_state);
        !           779:        PF_MD5_UPD(rule, proto);
        !           780:        PF_MD5_UPD(rule, type);
        !           781:        PF_MD5_UPD(rule, code);
        !           782:        PF_MD5_UPD(rule, flags);
        !           783:        PF_MD5_UPD(rule, flagset);
        !           784:        PF_MD5_UPD(rule, allow_opts);
        !           785:        PF_MD5_UPD(rule, rt);
        !           786:        PF_MD5_UPD(rule, tos);
        !           787: }
        !           788:
        !           789: int
        !           790: pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
        !           791: {
        !           792:        struct pf_ruleset       *rs;
        !           793:        struct pf_rule          *rule, **old_array;
        !           794:        struct pf_rulequeue     *old_rules;
        !           795:        int                      s, error;
        !           796:        u_int32_t                old_rcount;
        !           797:
        !           798:        if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
        !           799:                return (EINVAL);
        !           800:        rs = pf_find_ruleset(anchor);
        !           801:        if (rs == NULL || !rs->rules[rs_num].inactive.open ||
        !           802:            ticket != rs->rules[rs_num].inactive.ticket)
        !           803:                return (EBUSY);
        !           804:
        !           805:        /* Calculate checksum for the main ruleset */
        !           806:        if (rs == &pf_main_ruleset) {
        !           807:                error = pf_setup_pfsync_matching(rs);
        !           808:                if (error != 0)
        !           809:                        return (error);
        !           810:        }
        !           811:
        !           812:        /* Swap rules, keep the old. */
        !           813:        s = splsoftnet();
        !           814:        old_rules = rs->rules[rs_num].active.ptr;
        !           815:        old_rcount = rs->rules[rs_num].active.rcount;
        !           816:        old_array = rs->rules[rs_num].active.ptr_array;
        !           817:
        !           818:        rs->rules[rs_num].active.ptr =
        !           819:            rs->rules[rs_num].inactive.ptr;
        !           820:        rs->rules[rs_num].active.ptr_array =
        !           821:            rs->rules[rs_num].inactive.ptr_array;
        !           822:        rs->rules[rs_num].active.rcount =
        !           823:            rs->rules[rs_num].inactive.rcount;
        !           824:        rs->rules[rs_num].inactive.ptr = old_rules;
        !           825:        rs->rules[rs_num].inactive.ptr_array = old_array;
        !           826:        rs->rules[rs_num].inactive.rcount = old_rcount;
        !           827:
        !           828:        rs->rules[rs_num].active.ticket =
        !           829:            rs->rules[rs_num].inactive.ticket;
        !           830:        pf_calc_skip_steps(rs->rules[rs_num].active.ptr);
        !           831:
        !           832:
        !           833:        /* Purge the old rule list. */
        !           834:        while ((rule = TAILQ_FIRST(old_rules)) != NULL)
        !           835:                pf_rm_rule(old_rules, rule);
        !           836:        if (rs->rules[rs_num].inactive.ptr_array)
        !           837:                free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
        !           838:        rs->rules[rs_num].inactive.ptr_array = NULL;
        !           839:        rs->rules[rs_num].inactive.rcount = 0;
        !           840:        rs->rules[rs_num].inactive.open = 0;
        !           841:        pf_remove_if_empty_ruleset(rs);
        !           842:        splx(s);
        !           843:        return (0);
        !           844: }
        !           845:
        !           846: void
        !           847: pf_state_export(struct pfsync_state *sp, struct pf_state_key *sk,
        !           848:    struct pf_state *s)
        !           849: {
        !           850:        int secs = time_second;
        !           851:        bzero(sp, sizeof(struct pfsync_state));
        !           852:
        !           853:        /* copy from state key */
        !           854:        sp->lan.addr = sk->lan.addr;
        !           855:        sp->lan.port = sk->lan.port;
        !           856:        sp->gwy.addr = sk->gwy.addr;
        !           857:        sp->gwy.port = sk->gwy.port;
        !           858:        sp->ext.addr = sk->ext.addr;
        !           859:        sp->ext.port = sk->ext.port;
        !           860:        sp->proto = sk->proto;
        !           861:        sp->af = sk->af;
        !           862:        sp->direction = sk->direction;
        !           863:
        !           864:        /* copy from state */
        !           865:        memcpy(&sp->id, &s->id, sizeof(sp->id));
        !           866:        sp->creatorid = s->creatorid;
        !           867:        strlcpy(sp->ifname, s->kif->pfik_name, sizeof(sp->ifname));
        !           868:        pf_state_peer_to_pfsync(&s->src, &sp->src);
        !           869:        pf_state_peer_to_pfsync(&s->dst, &sp->dst);
        !           870:
        !           871:        sp->rule = s->rule.ptr->nr;
        !           872:        sp->nat_rule = (s->nat_rule.ptr == NULL) ?  -1 : s->nat_rule.ptr->nr;
        !           873:        sp->anchor = (s->anchor.ptr == NULL) ?  -1 : s->anchor.ptr->nr;
        !           874:
        !           875:        pf_state_counter_to_pfsync(s->bytes[0], sp->bytes[0]);
        !           876:        pf_state_counter_to_pfsync(s->bytes[1], sp->bytes[1]);
        !           877:        pf_state_counter_to_pfsync(s->packets[0], sp->packets[0]);
        !           878:        pf_state_counter_to_pfsync(s->packets[1], sp->packets[1]);
        !           879:        sp->creation = secs - s->creation;
        !           880:        sp->expire = pf_state_expires(s);
        !           881:        sp->log = s->log;
        !           882:        sp->allow_opts = s->allow_opts;
        !           883:        sp->timeout = s->timeout;
        !           884:
        !           885:        if (s->src_node)
        !           886:                sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
        !           887:        if (s->nat_src_node)
        !           888:                sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
        !           889:
        !           890:        if (sp->expire > secs)
        !           891:                sp->expire -= secs;
        !           892:        else
        !           893:                sp->expire = 0;
        !           894:
        !           895: }
        !           896:
        !           897: void
        !           898: pf_state_import(struct pfsync_state *sp, struct pf_state_key *sk,
        !           899:    struct pf_state *s)
        !           900: {
        !           901:        /* copy to state key */
        !           902:        sk->lan.addr = sp->lan.addr;
        !           903:        sk->lan.port = sp->lan.port;
        !           904:        sk->gwy.addr = sp->gwy.addr;
        !           905:        sk->gwy.port = sp->gwy.port;
        !           906:        sk->ext.addr = sp->ext.addr;
        !           907:        sk->ext.port = sp->ext.port;
        !           908:        sk->proto = sp->proto;
        !           909:        sk->af = sp->af;
        !           910:        sk->direction = sp->direction;
        !           911:
        !           912:        /* copy to state */
        !           913:        memcpy(&s->id, &sp->id, sizeof(sp->id));
        !           914:        s->creatorid = sp->creatorid;
        !           915:        strlcpy(sp->ifname, s->kif->pfik_name, sizeof(sp->ifname));
        !           916:        pf_state_peer_from_pfsync(&sp->src, &s->src);
        !           917:        pf_state_peer_from_pfsync(&sp->dst, &s->dst);
        !           918:
        !           919:        s->rule.ptr = &pf_default_rule;
        !           920:        s->nat_rule.ptr = NULL;
        !           921:        s->anchor.ptr = NULL;
        !           922:        s->rt_kif = NULL;
        !           923:        s->creation = time_second;
        !           924:        s->pfsync_time = 0;
        !           925:        s->packets[0] = s->packets[1] = 0;
        !           926:        s->bytes[0] = s->bytes[1] = 0;
        !           927: }
        !           928:
        !           929: int
        !           930: pf_setup_pfsync_matching(struct pf_ruleset *rs)
        !           931: {
        !           932:        MD5_CTX                  ctx;
        !           933:        struct pf_rule          *rule;
        !           934:        int                      rs_cnt;
        !           935:        u_int8_t                 digest[PF_MD5_DIGEST_LENGTH];
        !           936:
        !           937:        MD5Init(&ctx);
        !           938:        for (rs_cnt = 0; rs_cnt < PF_RULESET_MAX; rs_cnt++) {
        !           939:                /* XXX PF_RULESET_SCRUB as well? */
        !           940:                if (rs_cnt == PF_RULESET_SCRUB)
        !           941:                        continue;
        !           942:
        !           943:                if (rs->rules[rs_cnt].inactive.ptr_array)
        !           944:                        free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
        !           945:                rs->rules[rs_cnt].inactive.ptr_array = NULL;
        !           946:
        !           947:                if (rs->rules[rs_cnt].inactive.rcount) {
        !           948:                        rs->rules[rs_cnt].inactive.ptr_array =
        !           949:                            malloc(sizeof(caddr_t) *
        !           950:                            rs->rules[rs_cnt].inactive.rcount,
        !           951:                            M_TEMP, M_NOWAIT);
        !           952:
        !           953:                        if (!rs->rules[rs_cnt].inactive.ptr_array)
        !           954:                                return (ENOMEM);
        !           955:                }
        !           956:
        !           957:                TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
        !           958:                    entries) {
        !           959:                        pf_hash_rule(&ctx, rule);
        !           960:                        (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
        !           961:                }
        !           962:        }
        !           963:
        !           964:        MD5Final(digest, &ctx);
        !           965:        memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum));
        !           966:        return (0);
        !           967: }
        !           968:
        !           969: int
        !           970: pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
        !           971: {
        !           972:        struct pf_pooladdr      *pa = NULL;
        !           973:        struct pf_pool          *pool = NULL;
        !           974:        int                      s;
        !           975:        int                      error = 0;
        !           976:
        !           977:        /* XXX keep in sync with switch() below */
        !           978:        if (securelevel > 1)
        !           979:                switch (cmd) {
        !           980:                case DIOCGETRULES:
        !           981:                case DIOCGETRULE:
        !           982:                case DIOCGETADDRS:
        !           983:                case DIOCGETADDR:
        !           984:                case DIOCGETSTATE:
        !           985:                case DIOCSETSTATUSIF:
        !           986:                case DIOCGETSTATUS:
        !           987:                case DIOCCLRSTATUS:
        !           988:                case DIOCNATLOOK:
        !           989:                case DIOCSETDEBUG:
        !           990:                case DIOCGETSTATES:
        !           991:                case DIOCGETTIMEOUT:
        !           992:                case DIOCCLRRULECTRS:
        !           993:                case DIOCGETLIMIT:
        !           994:                case DIOCGETALTQS:
        !           995:                case DIOCGETALTQ:
        !           996:                case DIOCGETQSTATS:
        !           997:                case DIOCGETRULESETS:
        !           998:                case DIOCGETRULESET:
        !           999:                case DIOCRGETTABLES:
        !          1000:                case DIOCRGETTSTATS:
        !          1001:                case DIOCRCLRTSTATS:
        !          1002:                case DIOCRCLRADDRS:
        !          1003:                case DIOCRADDADDRS:
        !          1004:                case DIOCRDELADDRS:
        !          1005:                case DIOCRSETADDRS:
        !          1006:                case DIOCRGETADDRS:
        !          1007:                case DIOCRGETASTATS:
        !          1008:                case DIOCRCLRASTATS:
        !          1009:                case DIOCRTSTADDRS:
        !          1010:                case DIOCOSFPGET:
        !          1011:                case DIOCGETSRCNODES:
        !          1012:                case DIOCCLRSRCNODES:
        !          1013:                case DIOCIGETIFACES:
        !          1014:                case DIOCSETIFFLAG:
        !          1015:                case DIOCCLRIFFLAG:
        !          1016:                        break;
        !          1017:                case DIOCRCLRTABLES:
        !          1018:                case DIOCRADDTABLES:
        !          1019:                case DIOCRDELTABLES:
        !          1020:                case DIOCRSETTFLAGS:
        !          1021:                        if (((struct pfioc_table *)addr)->pfrio_flags &
        !          1022:                            PFR_FLAG_DUMMY)
        !          1023:                                break; /* dummy operation ok */
        !          1024:                        return (EPERM);
        !          1025:                default:
        !          1026:                        return (EPERM);
        !          1027:                }
        !          1028:
        !          1029:        if (!(flags & FWRITE))
        !          1030:                switch (cmd) {
        !          1031:                case DIOCGETRULES:
        !          1032:                case DIOCGETADDRS:
        !          1033:                case DIOCGETADDR:
        !          1034:                case DIOCGETSTATE:
        !          1035:                case DIOCGETSTATUS:
        !          1036:                case DIOCGETSTATES:
        !          1037:                case DIOCGETTIMEOUT:
        !          1038:                case DIOCGETLIMIT:
        !          1039:                case DIOCGETALTQS:
        !          1040:                case DIOCGETALTQ:
        !          1041:                case DIOCGETQSTATS:
        !          1042:                case DIOCGETRULESETS:
        !          1043:                case DIOCGETRULESET:
        !          1044:                case DIOCNATLOOK:
        !          1045:                case DIOCRGETTABLES:
        !          1046:                case DIOCRGETTSTATS:
        !          1047:                case DIOCRGETADDRS:
        !          1048:                case DIOCRGETASTATS:
        !          1049:                case DIOCRTSTADDRS:
        !          1050:                case DIOCOSFPGET:
        !          1051:                case DIOCGETSRCNODES:
        !          1052:                case DIOCIGETIFACES:
        !          1053:                        break;
        !          1054:                case DIOCRCLRTABLES:
        !          1055:                case DIOCRADDTABLES:
        !          1056:                case DIOCRDELTABLES:
        !          1057:                case DIOCRCLRTSTATS:
        !          1058:                case DIOCRCLRADDRS:
        !          1059:                case DIOCRADDADDRS:
        !          1060:                case DIOCRDELADDRS:
        !          1061:                case DIOCRSETADDRS:
        !          1062:                case DIOCRSETTFLAGS:
        !          1063:                        if (((struct pfioc_table *)addr)->pfrio_flags &
        !          1064:                            PFR_FLAG_DUMMY) {
        !          1065:                                flags |= FWRITE; /* need write lock for dummy */
        !          1066:                                break; /* dummy operation ok */
        !          1067:                        }
        !          1068:                        return (EACCES);
        !          1069:                case DIOCGETRULE:
        !          1070:                        if (((struct pfioc_rule *)addr)->action == PF_GET_CLR_CNTR)
        !          1071:                                return (EACCES);
        !          1072:                        break;
        !          1073:                default:
        !          1074:                        return (EACCES);
        !          1075:                }
        !          1076:
        !          1077:        if (flags & FWRITE)
        !          1078:                rw_enter_write(&pf_consistency_lock);
        !          1079:        else
        !          1080:                rw_enter_read(&pf_consistency_lock);
        !          1081:
        !          1082:        s = splsoftnet();
        !          1083:        switch (cmd) {
        !          1084:
        !          1085:        case DIOCSTART:
        !          1086:                if (pf_status.running)
        !          1087:                        error = EEXIST;
        !          1088:                else {
        !          1089:                        pf_status.running = 1;
        !          1090:                        pf_status.since = time_second;
        !          1091:                        if (pf_status.stateid == 0) {
        !          1092:                                pf_status.stateid = time_second;
        !          1093:                                pf_status.stateid = pf_status.stateid << 32;
        !          1094:                        }
        !          1095:                        DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
        !          1096:                }
        !          1097:                break;
        !          1098:
        !          1099:        case DIOCSTOP:
        !          1100:                if (!pf_status.running)
        !          1101:                        error = ENOENT;
        !          1102:                else {
        !          1103:                        pf_status.running = 0;
        !          1104:                        pf_status.since = time_second;
        !          1105:                        DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
        !          1106:                }
        !          1107:                break;
        !          1108:
        !          1109:        case DIOCADDRULE: {
        !          1110:                struct pfioc_rule       *pr = (struct pfioc_rule *)addr;
        !          1111:                struct pf_ruleset       *ruleset;
        !          1112:                struct pf_rule          *rule, *tail;
        !          1113:                struct pf_pooladdr      *pa;
        !          1114:                int                      rs_num;
        !          1115:
        !          1116:                pr->anchor[sizeof(pr->anchor) - 1] = 0;
        !          1117:                ruleset = pf_find_ruleset(pr->anchor);
        !          1118:                if (ruleset == NULL) {
        !          1119:                        error = EINVAL;
        !          1120:                        break;
        !          1121:                }
        !          1122:                rs_num = pf_get_ruleset_number(pr->rule.action);
        !          1123:                if (rs_num >= PF_RULESET_MAX) {
        !          1124:                        error = EINVAL;
        !          1125:                        break;
        !          1126:                }
        !          1127:                if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
        !          1128:                        error = EINVAL;
        !          1129:                        break;
        !          1130:                }
        !          1131:                if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
        !          1132:                        error = EBUSY;
        !          1133:                        break;
        !          1134:                }
        !          1135:                if (pr->pool_ticket != ticket_pabuf) {
        !          1136:                        error = EBUSY;
        !          1137:                        break;
        !          1138:                }
        !          1139:                rule = pool_get(&pf_rule_pl, PR_NOWAIT);
        !          1140:                if (rule == NULL) {
        !          1141:                        error = ENOMEM;
        !          1142:                        break;
        !          1143:                }
        !          1144:                bcopy(&pr->rule, rule, sizeof(struct pf_rule));
        !          1145:                rule->cuid = p->p_cred->p_ruid;
        !          1146:                rule->cpid = p->p_pid;
        !          1147:                rule->anchor = NULL;
        !          1148:                rule->kif = NULL;
        !          1149:                TAILQ_INIT(&rule->rpool.list);
        !          1150:                /* initialize refcounting */
        !          1151:                rule->states = 0;
        !          1152:                rule->src_nodes = 0;
        !          1153:                rule->entries.tqe_prev = NULL;
        !          1154: #ifndef INET
        !          1155:                if (rule->af == AF_INET) {
        !          1156:                        pool_put(&pf_rule_pl, rule);
        !          1157:                        error = EAFNOSUPPORT;
        !          1158:                        break;
        !          1159:                }
        !          1160: #endif /* INET */
        !          1161: #ifndef INET6
        !          1162:                if (rule->af == AF_INET6) {
        !          1163:                        pool_put(&pf_rule_pl, rule);
        !          1164:                        error = EAFNOSUPPORT;
        !          1165:                        break;
        !          1166:                }
        !          1167: #endif /* INET6 */
        !          1168:                tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
        !          1169:                    pf_rulequeue);
        !          1170:                if (tail)
        !          1171:                        rule->nr = tail->nr + 1;
        !          1172:                else
        !          1173:                        rule->nr = 0;
        !          1174:                if (rule->ifname[0]) {
        !          1175:                        rule->kif = pfi_kif_get(rule->ifname);
        !          1176:                        if (rule->kif == NULL) {
        !          1177:                                pool_put(&pf_rule_pl, rule);
        !          1178:                                error = EINVAL;
        !          1179:                                break;
        !          1180:                        }
        !          1181:                        pfi_kif_ref(rule->kif, PFI_KIF_REF_RULE);
        !          1182:                }
        !          1183:
        !          1184:                if (rule->rtableid > 0 && !rtable_exists(rule->rtableid))
        !          1185:                        error = EBUSY;
        !          1186:
        !          1187: #ifdef ALTQ
        !          1188:                /* set queue IDs */
        !          1189:                if (rule->qname[0] != 0) {
        !          1190:                        if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
        !          1191:                                error = EBUSY;
        !          1192:                        else if (rule->pqname[0] != 0) {
        !          1193:                                if ((rule->pqid =
        !          1194:                                    pf_qname2qid(rule->pqname)) == 0)
        !          1195:                                        error = EBUSY;
        !          1196:                        } else
        !          1197:                                rule->pqid = rule->qid;
        !          1198:                }
        !          1199: #endif
        !          1200:                if (rule->tagname[0])
        !          1201:                        if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
        !          1202:                                error = EBUSY;
        !          1203:                if (rule->match_tagname[0])
        !          1204:                        if ((rule->match_tag =
        !          1205:                            pf_tagname2tag(rule->match_tagname)) == 0)
        !          1206:                                error = EBUSY;
        !          1207:                if (rule->rt && !rule->direction)
        !          1208:                        error = EINVAL;
        !          1209: #if NPFLOG > 0
        !          1210:                if (!rule->log)
        !          1211:                        rule->logif = 0;
        !          1212:                if (rule->logif >= PFLOGIFS_MAX)
        !          1213:                        error = EINVAL;
        !          1214: #endif
        !          1215:                if (pf_rtlabel_add(&rule->src.addr) ||
        !          1216:                    pf_rtlabel_add(&rule->dst.addr))
        !          1217:                        error = EBUSY;
        !          1218:                if (pfi_dynaddr_setup(&rule->src.addr, rule->af))
        !          1219:                        error = EINVAL;
        !          1220:                if (pfi_dynaddr_setup(&rule->dst.addr, rule->af))
        !          1221:                        error = EINVAL;
        !          1222:                if (pf_tbladdr_setup(ruleset, &rule->src.addr))
        !          1223:                        error = EINVAL;
        !          1224:                if (pf_tbladdr_setup(ruleset, &rule->dst.addr))
        !          1225:                        error = EINVAL;
        !          1226:                if (pf_anchor_setup(rule, ruleset, pr->anchor_call))
        !          1227:                        error = EINVAL;
        !          1228:                TAILQ_FOREACH(pa, &pf_pabuf, entries)
        !          1229:                        if (pf_tbladdr_setup(ruleset, &pa->addr))
        !          1230:                                error = EINVAL;
        !          1231:
        !          1232:                if (rule->overload_tblname[0]) {
        !          1233:                        if ((rule->overload_tbl = pfr_attach_table(ruleset,
        !          1234:                            rule->overload_tblname)) == NULL)
        !          1235:                                error = EINVAL;
        !          1236:                        else
        !          1237:                                rule->overload_tbl->pfrkt_flags |=
        !          1238:                                    PFR_TFLAG_ACTIVE;
        !          1239:                }
        !          1240:
        !          1241:                pf_mv_pool(&pf_pabuf, &rule->rpool.list);
        !          1242:                if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
        !          1243:                    (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
        !          1244:                    (rule->rt > PF_FASTROUTE)) &&
        !          1245:                    (TAILQ_FIRST(&rule->rpool.list) == NULL))
        !          1246:                        error = EINVAL;
        !          1247:
        !          1248:                if (error) {
        !          1249:                        pf_rm_rule(NULL, rule);
        !          1250:                        break;
        !          1251:                }
        !          1252:                rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
        !          1253:                rule->evaluations = rule->packets[0] = rule->packets[1] =
        !          1254:                    rule->bytes[0] = rule->bytes[1] = 0;
        !          1255:                TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
        !          1256:                    rule, entries);
        !          1257:                ruleset->rules[rs_num].inactive.rcount++;
        !          1258:                break;
        !          1259:        }
        !          1260:
        !          1261:        case DIOCGETRULES: {
        !          1262:                struct pfioc_rule       *pr = (struct pfioc_rule *)addr;
        !          1263:                struct pf_ruleset       *ruleset;
        !          1264:                struct pf_rule          *tail;
        !          1265:                int                      rs_num;
        !          1266:
        !          1267:                pr->anchor[sizeof(pr->anchor) - 1] = 0;
        !          1268:                ruleset = pf_find_ruleset(pr->anchor);
        !          1269:                if (ruleset == NULL) {
        !          1270:                        error = EINVAL;
        !          1271:                        break;
        !          1272:                }
        !          1273:                rs_num = pf_get_ruleset_number(pr->rule.action);
        !          1274:                if (rs_num >= PF_RULESET_MAX) {
        !          1275:                        error = EINVAL;
        !          1276:                        break;
        !          1277:                }
        !          1278:                tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
        !          1279:                    pf_rulequeue);
        !          1280:                if (tail)
        !          1281:                        pr->nr = tail->nr + 1;
        !          1282:                else
        !          1283:                        pr->nr = 0;
        !          1284:                pr->ticket = ruleset->rules[rs_num].active.ticket;
        !          1285:                break;
        !          1286:        }
        !          1287:
        !          1288:        case DIOCGETRULE: {
        !          1289:                struct pfioc_rule       *pr = (struct pfioc_rule *)addr;
        !          1290:                struct pf_ruleset       *ruleset;
        !          1291:                struct pf_rule          *rule;
        !          1292:                int                      rs_num, i;
        !          1293:
        !          1294:                pr->anchor[sizeof(pr->anchor) - 1] = 0;
        !          1295:                ruleset = pf_find_ruleset(pr->anchor);
        !          1296:                if (ruleset == NULL) {
        !          1297:                        error = EINVAL;
        !          1298:                        break;
        !          1299:                }
        !          1300:                rs_num = pf_get_ruleset_number(pr->rule.action);
        !          1301:                if (rs_num >= PF_RULESET_MAX) {
        !          1302:                        error = EINVAL;
        !          1303:                        break;
        !          1304:                }
        !          1305:                if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
        !          1306:                        error = EBUSY;
        !          1307:                        break;
        !          1308:                }
        !          1309:                rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
        !          1310:                while ((rule != NULL) && (rule->nr != pr->nr))
        !          1311:                        rule = TAILQ_NEXT(rule, entries);
        !          1312:                if (rule == NULL) {
        !          1313:                        error = EBUSY;
        !          1314:                        break;
        !          1315:                }
        !          1316:                bcopy(rule, &pr->rule, sizeof(struct pf_rule));
        !          1317:                if (pf_anchor_copyout(ruleset, rule, pr)) {
        !          1318:                        error = EBUSY;
        !          1319:                        break;
        !          1320:                }
        !          1321:                pfi_dynaddr_copyout(&pr->rule.src.addr);
        !          1322:                pfi_dynaddr_copyout(&pr->rule.dst.addr);
        !          1323:                pf_tbladdr_copyout(&pr->rule.src.addr);
        !          1324:                pf_tbladdr_copyout(&pr->rule.dst.addr);
        !          1325:                pf_rtlabel_copyout(&pr->rule.src.addr);
        !          1326:                pf_rtlabel_copyout(&pr->rule.dst.addr);
        !          1327:                for (i = 0; i < PF_SKIP_COUNT; ++i)
        !          1328:                        if (rule->skip[i].ptr == NULL)
        !          1329:                                pr->rule.skip[i].nr = -1;
        !          1330:                        else
        !          1331:                                pr->rule.skip[i].nr =
        !          1332:                                    rule->skip[i].ptr->nr;
        !          1333:
        !          1334:                if (pr->action == PF_GET_CLR_CNTR) {
        !          1335:                        rule->evaluations = 0;
        !          1336:                        rule->packets[0] = rule->packets[1] = 0;
        !          1337:                        rule->bytes[0] = rule->bytes[1] = 0;
        !          1338:                }
        !          1339:                break;
        !          1340:        }
        !          1341:
        !          1342:        case DIOCCHANGERULE: {
        !          1343:                struct pfioc_rule       *pcr = (struct pfioc_rule *)addr;
        !          1344:                struct pf_ruleset       *ruleset;
        !          1345:                struct pf_rule          *oldrule = NULL, *newrule = NULL;
        !          1346:                u_int32_t                nr = 0;
        !          1347:                int                      rs_num;
        !          1348:
        !          1349:                if (!(pcr->action == PF_CHANGE_REMOVE ||
        !          1350:                    pcr->action == PF_CHANGE_GET_TICKET) &&
        !          1351:                    pcr->pool_ticket != ticket_pabuf) {
        !          1352:                        error = EBUSY;
        !          1353:                        break;
        !          1354:                }
        !          1355:
        !          1356:                if (pcr->action < PF_CHANGE_ADD_HEAD ||
        !          1357:                    pcr->action > PF_CHANGE_GET_TICKET) {
        !          1358:                        error = EINVAL;
        !          1359:                        break;
        !          1360:                }
        !          1361:                ruleset = pf_find_ruleset(pcr->anchor);
        !          1362:                if (ruleset == NULL) {
        !          1363:                        error = EINVAL;
        !          1364:                        break;
        !          1365:                }
        !          1366:                rs_num = pf_get_ruleset_number(pcr->rule.action);
        !          1367:                if (rs_num >= PF_RULESET_MAX) {
        !          1368:                        error = EINVAL;
        !          1369:                        break;
        !          1370:                }
        !          1371:
        !          1372:                if (pcr->action == PF_CHANGE_GET_TICKET) {
        !          1373:                        pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
        !          1374:                        break;
        !          1375:                } else {
        !          1376:                        if (pcr->ticket !=
        !          1377:                            ruleset->rules[rs_num].active.ticket) {
        !          1378:                                error = EINVAL;
        !          1379:                                break;
        !          1380:                        }
        !          1381:                        if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
        !          1382:                                error = EINVAL;
        !          1383:                                break;
        !          1384:                        }
        !          1385:                }
        !          1386:
        !          1387:                if (pcr->action != PF_CHANGE_REMOVE) {
        !          1388:                        newrule = pool_get(&pf_rule_pl, PR_NOWAIT);
        !          1389:                        if (newrule == NULL) {
        !          1390:                                error = ENOMEM;
        !          1391:                                break;
        !          1392:                        }
        !          1393:                        bcopy(&pcr->rule, newrule, sizeof(struct pf_rule));
        !          1394:                        newrule->cuid = p->p_cred->p_ruid;
        !          1395:                        newrule->cpid = p->p_pid;
        !          1396:                        TAILQ_INIT(&newrule->rpool.list);
        !          1397:                        /* initialize refcounting */
        !          1398:                        newrule->states = 0;
        !          1399:                        newrule->entries.tqe_prev = NULL;
        !          1400: #ifndef INET
        !          1401:                        if (newrule->af == AF_INET) {
        !          1402:                                pool_put(&pf_rule_pl, newrule);
        !          1403:                                error = EAFNOSUPPORT;
        !          1404:                                break;
        !          1405:                        }
        !          1406: #endif /* INET */
        !          1407: #ifndef INET6
        !          1408:                        if (newrule->af == AF_INET6) {
        !          1409:                                pool_put(&pf_rule_pl, newrule);
        !          1410:                                error = EAFNOSUPPORT;
        !          1411:                                break;
        !          1412:                        }
        !          1413: #endif /* INET6 */
        !          1414:                        if (newrule->ifname[0]) {
        !          1415:                                newrule->kif = pfi_kif_get(newrule->ifname);
        !          1416:                                if (newrule->kif == NULL) {
        !          1417:                                        pool_put(&pf_rule_pl, newrule);
        !          1418:                                        error = EINVAL;
        !          1419:                                        break;
        !          1420:                                }
        !          1421:                                pfi_kif_ref(newrule->kif, PFI_KIF_REF_RULE);
        !          1422:                        } else
        !          1423:                                newrule->kif = NULL;
        !          1424:
        !          1425:                        if (newrule->rtableid > 0 &&
        !          1426:                            !rtable_exists(newrule->rtableid))
        !          1427:                                error = EBUSY;
        !          1428:
        !          1429: #ifdef ALTQ
        !          1430:                        /* set queue IDs */
        !          1431:                        if (newrule->qname[0] != 0) {
        !          1432:                                if ((newrule->qid =
        !          1433:                                    pf_qname2qid(newrule->qname)) == 0)
        !          1434:                                        error = EBUSY;
        !          1435:                                else if (newrule->pqname[0] != 0) {
        !          1436:                                        if ((newrule->pqid =
        !          1437:                                            pf_qname2qid(newrule->pqname)) == 0)
        !          1438:                                                error = EBUSY;
        !          1439:                                } else
        !          1440:                                        newrule->pqid = newrule->qid;
        !          1441:                        }
        !          1442: #endif /* ALTQ */
        !          1443:                        if (newrule->tagname[0])
        !          1444:                                if ((newrule->tag =
        !          1445:                                    pf_tagname2tag(newrule->tagname)) == 0)
        !          1446:                                        error = EBUSY;
        !          1447:                        if (newrule->match_tagname[0])
        !          1448:                                if ((newrule->match_tag = pf_tagname2tag(
        !          1449:                                    newrule->match_tagname)) == 0)
        !          1450:                                        error = EBUSY;
        !          1451:                        if (newrule->rt && !newrule->direction)
        !          1452:                                error = EINVAL;
        !          1453: #if NPFLOG > 0
        !          1454:                        if (!newrule->log)
        !          1455:                                newrule->logif = 0;
        !          1456:                        if (newrule->logif >= PFLOGIFS_MAX)
        !          1457:                                error = EINVAL;
        !          1458: #endif
        !          1459:                        if (pf_rtlabel_add(&newrule->src.addr) ||
        !          1460:                            pf_rtlabel_add(&newrule->dst.addr))
        !          1461:                                error = EBUSY;
        !          1462:                        if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af))
        !          1463:                                error = EINVAL;
        !          1464:                        if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af))
        !          1465:                                error = EINVAL;
        !          1466:                        if (pf_tbladdr_setup(ruleset, &newrule->src.addr))
        !          1467:                                error = EINVAL;
        !          1468:                        if (pf_tbladdr_setup(ruleset, &newrule->dst.addr))
        !          1469:                                error = EINVAL;
        !          1470:                        if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call))
        !          1471:                                error = EINVAL;
        !          1472:                        TAILQ_FOREACH(pa, &pf_pabuf, entries)
        !          1473:                                if (pf_tbladdr_setup(ruleset, &pa->addr))
        !          1474:                                        error = EINVAL;
        !          1475:
        !          1476:                        if (newrule->overload_tblname[0]) {
        !          1477:                                if ((newrule->overload_tbl = pfr_attach_table(
        !          1478:                                    ruleset, newrule->overload_tblname)) ==
        !          1479:                                    NULL)
        !          1480:                                        error = EINVAL;
        !          1481:                                else
        !          1482:                                        newrule->overload_tbl->pfrkt_flags |=
        !          1483:                                            PFR_TFLAG_ACTIVE;
        !          1484:                        }
        !          1485:
        !          1486:                        pf_mv_pool(&pf_pabuf, &newrule->rpool.list);
        !          1487:                        if (((((newrule->action == PF_NAT) ||
        !          1488:                            (newrule->action == PF_RDR) ||
        !          1489:                            (newrule->action == PF_BINAT) ||
        !          1490:                            (newrule->rt > PF_FASTROUTE)) &&
        !          1491:                            !newrule->anchor)) &&
        !          1492:                            (TAILQ_FIRST(&newrule->rpool.list) == NULL))
        !          1493:                                error = EINVAL;
        !          1494:
        !          1495:                        if (error) {
        !          1496:                                pf_rm_rule(NULL, newrule);
        !          1497:                                break;
        !          1498:                        }
        !          1499:                        newrule->rpool.cur = TAILQ_FIRST(&newrule->rpool.list);
        !          1500:                        newrule->evaluations = 0;
        !          1501:                        newrule->packets[0] = newrule->packets[1] = 0;
        !          1502:                        newrule->bytes[0] = newrule->bytes[1] = 0;
        !          1503:                }
        !          1504:                pf_empty_pool(&pf_pabuf);
        !          1505:
        !          1506:                if (pcr->action == PF_CHANGE_ADD_HEAD)
        !          1507:                        oldrule = TAILQ_FIRST(
        !          1508:                            ruleset->rules[rs_num].active.ptr);
        !          1509:                else if (pcr->action == PF_CHANGE_ADD_TAIL)
        !          1510:                        oldrule = TAILQ_LAST(
        !          1511:                            ruleset->rules[rs_num].active.ptr, pf_rulequeue);
        !          1512:                else {
        !          1513:                        oldrule = TAILQ_FIRST(
        !          1514:                            ruleset->rules[rs_num].active.ptr);
        !          1515:                        while ((oldrule != NULL) && (oldrule->nr != pcr->nr))
        !          1516:                                oldrule = TAILQ_NEXT(oldrule, entries);
        !          1517:                        if (oldrule == NULL) {
        !          1518:                                if (newrule != NULL)
        !          1519:                                        pf_rm_rule(NULL, newrule);
        !          1520:                                error = EINVAL;
        !          1521:                                break;
        !          1522:                        }
        !          1523:                }
        !          1524:
        !          1525:                if (pcr->action == PF_CHANGE_REMOVE) {
        !          1526:                        pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
        !          1527:                        ruleset->rules[rs_num].active.rcount--;
        !          1528:                } else {
        !          1529:                        if (oldrule == NULL)
        !          1530:                                TAILQ_INSERT_TAIL(
        !          1531:                                    ruleset->rules[rs_num].active.ptr,
        !          1532:                                    newrule, entries);
        !          1533:                        else if (pcr->action == PF_CHANGE_ADD_HEAD ||
        !          1534:                            pcr->action == PF_CHANGE_ADD_BEFORE)
        !          1535:                                TAILQ_INSERT_BEFORE(oldrule, newrule, entries);
        !          1536:                        else
        !          1537:                                TAILQ_INSERT_AFTER(
        !          1538:                                    ruleset->rules[rs_num].active.ptr,
        !          1539:                                    oldrule, newrule, entries);
        !          1540:                        ruleset->rules[rs_num].active.rcount++;
        !          1541:                }
        !          1542:
        !          1543:                nr = 0;
        !          1544:                TAILQ_FOREACH(oldrule,
        !          1545:                    ruleset->rules[rs_num].active.ptr, entries)
        !          1546:                        oldrule->nr = nr++;
        !          1547:
        !          1548:                ruleset->rules[rs_num].active.ticket++;
        !          1549:
        !          1550:                pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
        !          1551:                pf_remove_if_empty_ruleset(ruleset);
        !          1552:
        !          1553:                break;
        !          1554:        }
        !          1555:
        !          1556:        case DIOCCLRSTATES: {
        !          1557:                struct pf_state         *s, *nexts;
        !          1558:                struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
        !          1559:                int                      killed = 0;
        !          1560:
        !          1561:                for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) {
        !          1562:                        nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
        !          1563:
        !          1564:                        if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
        !          1565:                            s->kif->pfik_name)) {
        !          1566: #if NPFSYNC
        !          1567:                                /* don't send out individual delete messages */
        !          1568:                                s->sync_flags = PFSTATE_NOSYNC;
        !          1569: #endif
        !          1570:                                pf_unlink_state(s);
        !          1571:                                killed++;
        !          1572:                        }
        !          1573:                }
        !          1574:                psk->psk_af = killed;
        !          1575: #if NPFSYNC
        !          1576:                pfsync_clear_states(pf_status.hostid, psk->psk_ifname);
        !          1577: #endif
        !          1578:                break;
        !          1579:        }
        !          1580:
        !          1581:        case DIOCKILLSTATES: {
        !          1582:                struct pf_state         *s, *nexts;
        !          1583:                struct pf_state_key     *sk;
        !          1584:                struct pf_state_host    *src, *dst;
        !          1585:                struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr;
        !          1586:                int                      killed = 0;
        !          1587:
        !          1588:                for (s = RB_MIN(pf_state_tree_id, &tree_id); s;
        !          1589:                    s = nexts) {
        !          1590:                        nexts = RB_NEXT(pf_state_tree_id, &tree_id, s);
        !          1591:                        sk = s->state_key;
        !          1592:
        !          1593:                        if (sk->direction == PF_OUT) {
        !          1594:                                src = &sk->lan;
        !          1595:                                dst = &sk->ext;
        !          1596:                        } else {
        !          1597:                                src = &sk->ext;
        !          1598:                                dst = &sk->lan;
        !          1599:                        }
        !          1600:                        if ((!psk->psk_af || sk->af == psk->psk_af)
        !          1601:                            && (!psk->psk_proto || psk->psk_proto ==
        !          1602:                            sk->proto) &&
        !          1603:                            PF_MATCHA(psk->psk_src.neg,
        !          1604:                            &psk->psk_src.addr.v.a.addr,
        !          1605:                            &psk->psk_src.addr.v.a.mask,
        !          1606:                            &src->addr, sk->af) &&
        !          1607:                            PF_MATCHA(psk->psk_dst.neg,
        !          1608:                            &psk->psk_dst.addr.v.a.addr,
        !          1609:                            &psk->psk_dst.addr.v.a.mask,
        !          1610:                            &dst->addr, sk->af) &&
        !          1611:                            (psk->psk_src.port_op == 0 ||
        !          1612:                            pf_match_port(psk->psk_src.port_op,
        !          1613:                            psk->psk_src.port[0], psk->psk_src.port[1],
        !          1614:                            src->port)) &&
        !          1615:                            (psk->psk_dst.port_op == 0 ||
        !          1616:                            pf_match_port(psk->psk_dst.port_op,
        !          1617:                            psk->psk_dst.port[0], psk->psk_dst.port[1],
        !          1618:                            dst->port)) &&
        !          1619:                            (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname,
        !          1620:                            s->kif->pfik_name))) {
        !          1621: #if NPFSYNC > 0
        !          1622:                                /* send immediate delete of state */
        !          1623:                                pfsync_delete_state(s);
        !          1624:                                s->sync_flags |= PFSTATE_NOSYNC;
        !          1625: #endif
        !          1626:                                pf_unlink_state(s);
        !          1627:                                killed++;
        !          1628:                        }
        !          1629:                }
        !          1630:                psk->psk_af = killed;
        !          1631:                break;
        !          1632:        }
        !          1633:
        !          1634:        case DIOCADDSTATE: {
        !          1635:                struct pfioc_state      *ps = (struct pfioc_state *)addr;
        !          1636:                struct pfsync_state     *sp = (struct pfsync_state *)ps->state;
        !          1637:                struct pf_state         *s;
        !          1638:                struct pf_state_key     *sk;
        !          1639:                struct pfi_kif          *kif;
        !          1640:
        !          1641:                if (sp->timeout >= PFTM_MAX &&
        !          1642:                    sp->timeout != PFTM_UNTIL_PACKET) {
        !          1643:                        error = EINVAL;
        !          1644:                        break;
        !          1645:                }
        !          1646:                s = pool_get(&pf_state_pl, PR_NOWAIT);
        !          1647:                if (s == NULL) {
        !          1648:                        error = ENOMEM;
        !          1649:                        break;
        !          1650:                }
        !          1651:                bzero(s, sizeof(struct pf_state));
        !          1652:                if ((sk = pf_alloc_state_key(s)) == NULL) {
        !          1653:                        error = ENOMEM;
        !          1654:                        break;
        !          1655:                }
        !          1656:                pf_state_import(sp, sk, s);
        !          1657:                kif = pfi_kif_get(sp->ifname);
        !          1658:                if (kif == NULL) {
        !          1659:                        pool_put(&pf_state_pl, s);
        !          1660:                        pool_put(&pf_state_key_pl, sk);
        !          1661:                        error = ENOENT;
        !          1662:                        break;
        !          1663:                }
        !          1664:                if (pf_insert_state(kif, s)) {
        !          1665:                        pfi_kif_unref(kif, PFI_KIF_REF_NONE);
        !          1666:                        pool_put(&pf_state_pl, s);
        !          1667:                        pool_put(&pf_state_key_pl, sk);
        !          1668:                        error = ENOMEM;
        !          1669:                }
        !          1670:                break;
        !          1671:        }
        !          1672:
        !          1673:        case DIOCGETSTATE: {
        !          1674:                struct pfioc_state      *ps = (struct pfioc_state *)addr;
        !          1675:                struct pf_state         *s;
        !          1676:                u_int32_t                nr;
        !          1677:
        !          1678:                nr = 0;
        !          1679:                RB_FOREACH(s, pf_state_tree_id, &tree_id) {
        !          1680:                        if (nr >= ps->nr)
        !          1681:                                break;
        !          1682:                        nr++;
        !          1683:                }
        !          1684:                if (s == NULL) {
        !          1685:                        error = EBUSY;
        !          1686:                        break;
        !          1687:                }
        !          1688:
        !          1689:                pf_state_export((struct pfsync_state *)&ps->state,
        !          1690:                    s->state_key, s);
        !          1691:                break;
        !          1692:        }
        !          1693:
        !          1694:        case DIOCGETSTATES: {
        !          1695:                struct pfioc_states     *ps = (struct pfioc_states *)addr;
        !          1696:                struct pf_state         *state;
        !          1697:                struct pfsync_state     *p, *pstore;
        !          1698:                u_int32_t                nr = 0;
        !          1699:
        !          1700:                if (ps->ps_len == 0) {
        !          1701:                        nr = pf_status.states;
        !          1702:                        ps->ps_len = sizeof(struct pfsync_state) * nr;
        !          1703:                        break;
        !          1704:                }
        !          1705:
        !          1706:                pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
        !          1707:
        !          1708:                p = ps->ps_states;
        !          1709:
        !          1710:                state = TAILQ_FIRST(&state_list);
        !          1711:                while (state) {
        !          1712:                        if (state->timeout != PFTM_UNLINKED) {
        !          1713:                                if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len)
        !          1714:                                        break;
        !          1715:
        !          1716:                                pf_state_export(pstore,
        !          1717:                                    state->state_key, state);
        !          1718:                                error = copyout(pstore, p, sizeof(*p));
        !          1719:                                if (error) {
        !          1720:                                        free(pstore, M_TEMP);
        !          1721:                                        goto fail;
        !          1722:                                }
        !          1723:                                p++;
        !          1724:                                nr++;
        !          1725:                        }
        !          1726:                        state = TAILQ_NEXT(state, entry_list);
        !          1727:                }
        !          1728:
        !          1729:                ps->ps_len = sizeof(struct pfsync_state) * nr;
        !          1730:
        !          1731:                free(pstore, M_TEMP);
        !          1732:                break;
        !          1733:        }
        !          1734:
        !          1735:        case DIOCGETSTATUS: {
        !          1736:                struct pf_status *s = (struct pf_status *)addr;
        !          1737:                bcopy(&pf_status, s, sizeof(struct pf_status));
        !          1738:                pfi_fill_oldstatus(s);
        !          1739:                break;
        !          1740:        }
        !          1741:
        !          1742:        case DIOCSETSTATUSIF: {
        !          1743:                struct pfioc_if *pi = (struct pfioc_if *)addr;
        !          1744:
        !          1745:                if (pi->ifname[0] == 0) {
        !          1746:                        bzero(pf_status.ifname, IFNAMSIZ);
        !          1747:                        break;
        !          1748:                }
        !          1749:                if (ifunit(pi->ifname) == NULL) {
        !          1750:                        error = EINVAL;
        !          1751:                        break;
        !          1752:                }
        !          1753:                strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ);
        !          1754:                break;
        !          1755:        }
        !          1756:
        !          1757:        case DIOCCLRSTATUS: {
        !          1758:                bzero(pf_status.counters, sizeof(pf_status.counters));
        !          1759:                bzero(pf_status.fcounters, sizeof(pf_status.fcounters));
        !          1760:                bzero(pf_status.scounters, sizeof(pf_status.scounters));
        !          1761:                pf_status.since = time_second;
        !          1762:                if (*pf_status.ifname)
        !          1763:                        pfi_clr_istats(pf_status.ifname);
        !          1764:                break;
        !          1765:        }
        !          1766:
        !          1767:        case DIOCNATLOOK: {
        !          1768:                struct pfioc_natlook    *pnl = (struct pfioc_natlook *)addr;
        !          1769:                struct pf_state_key     *sk;
        !          1770:                struct pf_state         *state;
        !          1771:                struct pf_state_key_cmp  key;
        !          1772:                int                      m = 0, direction = pnl->direction;
        !          1773:
        !          1774:                key.af = pnl->af;
        !          1775:                key.proto = pnl->proto;
        !          1776:
        !          1777:                if (!pnl->proto ||
        !          1778:                    PF_AZERO(&pnl->saddr, pnl->af) ||
        !          1779:                    PF_AZERO(&pnl->daddr, pnl->af) ||
        !          1780:                    ((pnl->proto == IPPROTO_TCP ||
        !          1781:                    pnl->proto == IPPROTO_UDP) &&
        !          1782:                    (!pnl->dport || !pnl->sport)))
        !          1783:                        error = EINVAL;
        !          1784:                else {
        !          1785:                        /*
        !          1786:                         * userland gives us source and dest of connection,
        !          1787:                         * reverse the lookup so we ask for what happens with
        !          1788:                         * the return traffic, enabling us to find it in the
        !          1789:                         * state tree.
        !          1790:                         */
        !          1791:                        if (direction == PF_IN) {
        !          1792:                                PF_ACPY(&key.ext.addr, &pnl->daddr, pnl->af);
        !          1793:                                key.ext.port = pnl->dport;
        !          1794:                                PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af);
        !          1795:                                key.gwy.port = pnl->sport;
        !          1796:                                state = pf_find_state_all(&key, PF_EXT_GWY, &m);
        !          1797:                        } else {
        !          1798:                                PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af);
        !          1799:                                key.lan.port = pnl->dport;
        !          1800:                                PF_ACPY(&key.ext.addr, &pnl->saddr, pnl->af);
        !          1801:                                key.ext.port = pnl->sport;
        !          1802:                                state = pf_find_state_all(&key, PF_LAN_EXT, &m);
        !          1803:                        }
        !          1804:                        if (m > 1)
        !          1805:                                error = E2BIG;  /* more than one state */
        !          1806:                        else if (state != NULL) {
        !          1807:                                sk = state->state_key;
        !          1808:                                if (direction == PF_IN) {
        !          1809:                                        PF_ACPY(&pnl->rsaddr, &sk->lan.addr,
        !          1810:                                            sk->af);
        !          1811:                                        pnl->rsport = sk->lan.port;
        !          1812:                                        PF_ACPY(&pnl->rdaddr, &pnl->daddr,
        !          1813:                                            pnl->af);
        !          1814:                                        pnl->rdport = pnl->dport;
        !          1815:                                } else {
        !          1816:                                        PF_ACPY(&pnl->rdaddr, &sk->gwy.addr,
        !          1817:                                            sk->af);
        !          1818:                                        pnl->rdport = sk->gwy.port;
        !          1819:                                        PF_ACPY(&pnl->rsaddr, &pnl->saddr,
        !          1820:                                            pnl->af);
        !          1821:                                        pnl->rsport = pnl->sport;
        !          1822:                                }
        !          1823:                        } else
        !          1824:                                error = ENOENT;
        !          1825:                }
        !          1826:                break;
        !          1827:        }
        !          1828:
        !          1829:        case DIOCSETTIMEOUT: {
        !          1830:                struct pfioc_tm *pt = (struct pfioc_tm *)addr;
        !          1831:                int              old;
        !          1832:
        !          1833:                if (pt->timeout < 0 || pt->timeout >= PFTM_MAX ||
        !          1834:                    pt->seconds < 0) {
        !          1835:                        error = EINVAL;
        !          1836:                        goto fail;
        !          1837:                }
        !          1838:                old = pf_default_rule.timeout[pt->timeout];
        !          1839:                if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0)
        !          1840:                        pt->seconds = 1;
        !          1841:                pf_default_rule.timeout[pt->timeout] = pt->seconds;
        !          1842:                if (pt->timeout == PFTM_INTERVAL && pt->seconds < old)
        !          1843:                        wakeup(pf_purge_thread);
        !          1844:                pt->seconds = old;
        !          1845:                break;
        !          1846:        }
        !          1847:
        !          1848:        case DIOCGETTIMEOUT: {
        !          1849:                struct pfioc_tm *pt = (struct pfioc_tm *)addr;
        !          1850:
        !          1851:                if (pt->timeout < 0 || pt->timeout >= PFTM_MAX) {
        !          1852:                        error = EINVAL;
        !          1853:                        goto fail;
        !          1854:                }
        !          1855:                pt->seconds = pf_default_rule.timeout[pt->timeout];
        !          1856:                break;
        !          1857:        }
        !          1858:
        !          1859:        case DIOCGETLIMIT: {
        !          1860:                struct pfioc_limit      *pl = (struct pfioc_limit *)addr;
        !          1861:
        !          1862:                if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
        !          1863:                        error = EINVAL;
        !          1864:                        goto fail;
        !          1865:                }
        !          1866:                pl->limit = pf_pool_limits[pl->index].limit;
        !          1867:                break;
        !          1868:        }
        !          1869:
        !          1870:        case DIOCSETLIMIT: {
        !          1871:                struct pfioc_limit      *pl = (struct pfioc_limit *)addr;
        !          1872:                int                      old_limit;
        !          1873:
        !          1874:                if (pl->index < 0 || pl->index >= PF_LIMIT_MAX ||
        !          1875:                    pf_pool_limits[pl->index].pp == NULL) {
        !          1876:                        error = EINVAL;
        !          1877:                        goto fail;
        !          1878:                }
        !          1879:                if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
        !          1880:                    pl->limit, NULL, 0) != 0) {
        !          1881:                        error = EBUSY;
        !          1882:                        goto fail;
        !          1883:                }
        !          1884:                old_limit = pf_pool_limits[pl->index].limit;
        !          1885:                pf_pool_limits[pl->index].limit = pl->limit;
        !          1886:                pl->limit = old_limit;
        !          1887:                break;
        !          1888:        }
        !          1889:
        !          1890:        case DIOCSETDEBUG: {
        !          1891:                u_int32_t       *level = (u_int32_t *)addr;
        !          1892:
        !          1893:                pf_status.debug = *level;
        !          1894:                break;
        !          1895:        }
        !          1896:
        !          1897:        case DIOCCLRRULECTRS: {
        !          1898:                /* obsoleted by DIOCGETRULE with action=PF_GET_CLR_CNTR */
        !          1899:                struct pf_ruleset       *ruleset = &pf_main_ruleset;
        !          1900:                struct pf_rule          *rule;
        !          1901:
        !          1902:                TAILQ_FOREACH(rule,
        !          1903:                    ruleset->rules[PF_RULESET_FILTER].active.ptr, entries) {
        !          1904:                        rule->evaluations = 0;
        !          1905:                        rule->packets[0] = rule->packets[1] = 0;
        !          1906:                        rule->bytes[0] = rule->bytes[1] = 0;
        !          1907:                }
        !          1908:                break;
        !          1909:        }
        !          1910:
        !          1911: #ifdef ALTQ
        !          1912:        case DIOCSTARTALTQ: {
        !          1913:                struct pf_altq          *altq;
        !          1914:
        !          1915:                /* enable all altq interfaces on active list */
        !          1916:                TAILQ_FOREACH(altq, pf_altqs_active, entries) {
        !          1917:                        if (altq->qname[0] == 0) {
        !          1918:                                error = pf_enable_altq(altq);
        !          1919:                                if (error != 0)
        !          1920:                                        break;
        !          1921:                        }
        !          1922:                }
        !          1923:                if (error == 0)
        !          1924:                        pf_altq_running = 1;
        !          1925:                DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
        !          1926:                break;
        !          1927:        }
        !          1928:
        !          1929:        case DIOCSTOPALTQ: {
        !          1930:                struct pf_altq          *altq;
        !          1931:
        !          1932:                /* disable all altq interfaces on active list */
        !          1933:                TAILQ_FOREACH(altq, pf_altqs_active, entries) {
        !          1934:                        if (altq->qname[0] == 0) {
        !          1935:                                error = pf_disable_altq(altq);
        !          1936:                                if (error != 0)
        !          1937:                                        break;
        !          1938:                        }
        !          1939:                }
        !          1940:                if (error == 0)
        !          1941:                        pf_altq_running = 0;
        !          1942:                DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
        !          1943:                break;
        !          1944:        }
        !          1945:
        !          1946:        case DIOCADDALTQ: {
        !          1947:                struct pfioc_altq       *pa = (struct pfioc_altq *)addr;
        !          1948:                struct pf_altq          *altq, *a;
        !          1949:
        !          1950:                if (pa->ticket != ticket_altqs_inactive) {
        !          1951:                        error = EBUSY;
        !          1952:                        break;
        !          1953:                }
        !          1954:                altq = pool_get(&pf_altq_pl, PR_NOWAIT);
        !          1955:                if (altq == NULL) {
        !          1956:                        error = ENOMEM;
        !          1957:                        break;
        !          1958:                }
        !          1959:                bcopy(&pa->altq, altq, sizeof(struct pf_altq));
        !          1960:
        !          1961:                /*
        !          1962:                 * if this is for a queue, find the discipline and
        !          1963:                 * copy the necessary fields
        !          1964:                 */
        !          1965:                if (altq->qname[0] != 0) {
        !          1966:                        if ((altq->qid = pf_qname2qid(altq->qname)) == 0) {
        !          1967:                                error = EBUSY;
        !          1968:                                pool_put(&pf_altq_pl, altq);
        !          1969:                                break;
        !          1970:                        }
        !          1971:                        TAILQ_FOREACH(a, pf_altqs_inactive, entries) {
        !          1972:                                if (strncmp(a->ifname, altq->ifname,
        !          1973:                                    IFNAMSIZ) == 0 && a->qname[0] == 0) {
        !          1974:                                        altq->altq_disc = a->altq_disc;
        !          1975:                                        break;
        !          1976:                                }
        !          1977:                        }
        !          1978:                }
        !          1979:
        !          1980:                error = altq_add(altq);
        !          1981:                if (error) {
        !          1982:                        pool_put(&pf_altq_pl, altq);
        !          1983:                        break;
        !          1984:                }
        !          1985:
        !          1986:                TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
        !          1987:                bcopy(altq, &pa->altq, sizeof(struct pf_altq));
        !          1988:                break;
        !          1989:        }
        !          1990:
        !          1991:        case DIOCGETALTQS: {
        !          1992:                struct pfioc_altq       *pa = (struct pfioc_altq *)addr;
        !          1993:                struct pf_altq          *altq;
        !          1994:
        !          1995:                pa->nr = 0;
        !          1996:                TAILQ_FOREACH(altq, pf_altqs_active, entries)
        !          1997:                        pa->nr++;
        !          1998:                pa->ticket = ticket_altqs_active;
        !          1999:                break;
        !          2000:        }
        !          2001:
        !          2002:        case DIOCGETALTQ: {
        !          2003:                struct pfioc_altq       *pa = (struct pfioc_altq *)addr;
        !          2004:                struct pf_altq          *altq;
        !          2005:                u_int32_t                nr;
        !          2006:
        !          2007:                if (pa->ticket != ticket_altqs_active) {
        !          2008:                        error = EBUSY;
        !          2009:                        break;
        !          2010:                }
        !          2011:                nr = 0;
        !          2012:                altq = TAILQ_FIRST(pf_altqs_active);
        !          2013:                while ((altq != NULL) && (nr < pa->nr)) {
        !          2014:                        altq = TAILQ_NEXT(altq, entries);
        !          2015:                        nr++;
        !          2016:                }
        !          2017:                if (altq == NULL) {
        !          2018:                        error = EBUSY;
        !          2019:                        break;
        !          2020:                }
        !          2021:                bcopy(altq, &pa->altq, sizeof(struct pf_altq));
        !          2022:                break;
        !          2023:        }
        !          2024:
        !          2025:        case DIOCCHANGEALTQ:
        !          2026:                /* CHANGEALTQ not supported yet! */
        !          2027:                error = ENODEV;
        !          2028:                break;
        !          2029:
        !          2030:        case DIOCGETQSTATS: {
        !          2031:                struct pfioc_qstats     *pq = (struct pfioc_qstats *)addr;
        !          2032:                struct pf_altq          *altq;
        !          2033:                u_int32_t                nr;
        !          2034:                int                      nbytes;
        !          2035:
        !          2036:                if (pq->ticket != ticket_altqs_active) {
        !          2037:                        error = EBUSY;
        !          2038:                        break;
        !          2039:                }
        !          2040:                nbytes = pq->nbytes;
        !          2041:                nr = 0;
        !          2042:                altq = TAILQ_FIRST(pf_altqs_active);
        !          2043:                while ((altq != NULL) && (nr < pq->nr)) {
        !          2044:                        altq = TAILQ_NEXT(altq, entries);
        !          2045:                        nr++;
        !          2046:                }
        !          2047:                if (altq == NULL) {
        !          2048:                        error = EBUSY;
        !          2049:                        break;
        !          2050:                }
        !          2051:                error = altq_getqstats(altq, pq->buf, &nbytes);
        !          2052:                if (error == 0) {
        !          2053:                        pq->scheduler = altq->scheduler;
        !          2054:                        pq->nbytes = nbytes;
        !          2055:                }
        !          2056:                break;
        !          2057:        }
        !          2058: #endif /* ALTQ */
        !          2059:
        !          2060:        case DIOCBEGINADDRS: {
        !          2061:                struct pfioc_pooladdr   *pp = (struct pfioc_pooladdr *)addr;
        !          2062:
        !          2063:                pf_empty_pool(&pf_pabuf);
        !          2064:                pp->ticket = ++ticket_pabuf;
        !          2065:                break;
        !          2066:        }
        !          2067:
        !          2068:        case DIOCADDADDR: {
        !          2069:                struct pfioc_pooladdr   *pp = (struct pfioc_pooladdr *)addr;
        !          2070:
        !          2071:                if (pp->ticket != ticket_pabuf) {
        !          2072:                        error = EBUSY;
        !          2073:                        break;
        !          2074:                }
        !          2075: #ifndef INET
        !          2076:                if (pp->af == AF_INET) {
        !          2077:                        error = EAFNOSUPPORT;
        !          2078:                        break;
        !          2079:                }
        !          2080: #endif /* INET */
        !          2081: #ifndef INET6
        !          2082:                if (pp->af == AF_INET6) {
        !          2083:                        error = EAFNOSUPPORT;
        !          2084:                        break;
        !          2085:                }
        !          2086: #endif /* INET6 */
        !          2087:                if (pp->addr.addr.type != PF_ADDR_ADDRMASK &&
        !          2088:                    pp->addr.addr.type != PF_ADDR_DYNIFTL &&
        !          2089:                    pp->addr.addr.type != PF_ADDR_TABLE) {
        !          2090:                        error = EINVAL;
        !          2091:                        break;
        !          2092:                }
        !          2093:                pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
        !          2094:                if (pa == NULL) {
        !          2095:                        error = ENOMEM;
        !          2096:                        break;
        !          2097:                }
        !          2098:                bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
        !          2099:                if (pa->ifname[0]) {
        !          2100:                        pa->kif = pfi_kif_get(pa->ifname);
        !          2101:                        if (pa->kif == NULL) {
        !          2102:                                pool_put(&pf_pooladdr_pl, pa);
        !          2103:                                error = EINVAL;
        !          2104:                                break;
        !          2105:                        }
        !          2106:                        pfi_kif_ref(pa->kif, PFI_KIF_REF_RULE);
        !          2107:                }
        !          2108:                if (pfi_dynaddr_setup(&pa->addr, pp->af)) {
        !          2109:                        pfi_dynaddr_remove(&pa->addr);
        !          2110:                        pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE);
        !          2111:                        pool_put(&pf_pooladdr_pl, pa);
        !          2112:                        error = EINVAL;
        !          2113:                        break;
        !          2114:                }
        !          2115:                TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
        !          2116:                break;
        !          2117:        }
        !          2118:
        !          2119:        case DIOCGETADDRS: {
        !          2120:                struct pfioc_pooladdr   *pp = (struct pfioc_pooladdr *)addr;
        !          2121:
        !          2122:                pp->nr = 0;
        !          2123:                pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
        !          2124:                    pp->r_num, 0, 1, 0);
        !          2125:                if (pool == NULL) {
        !          2126:                        error = EBUSY;
        !          2127:                        break;
        !          2128:                }
        !          2129:                TAILQ_FOREACH(pa, &pool->list, entries)
        !          2130:                        pp->nr++;
        !          2131:                break;
        !          2132:        }
        !          2133:
        !          2134:        case DIOCGETADDR: {
        !          2135:                struct pfioc_pooladdr   *pp = (struct pfioc_pooladdr *)addr;
        !          2136:                u_int32_t                nr = 0;
        !          2137:
        !          2138:                pool = pf_get_pool(pp->anchor, pp->ticket, pp->r_action,
        !          2139:                    pp->r_num, 0, 1, 1);
        !          2140:                if (pool == NULL) {
        !          2141:                        error = EBUSY;
        !          2142:                        break;
        !          2143:                }
        !          2144:                pa = TAILQ_FIRST(&pool->list);
        !          2145:                while ((pa != NULL) && (nr < pp->nr)) {
        !          2146:                        pa = TAILQ_NEXT(pa, entries);
        !          2147:                        nr++;
        !          2148:                }
        !          2149:                if (pa == NULL) {
        !          2150:                        error = EBUSY;
        !          2151:                        break;
        !          2152:                }
        !          2153:                bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
        !          2154:                pfi_dynaddr_copyout(&pp->addr.addr);
        !          2155:                pf_tbladdr_copyout(&pp->addr.addr);
        !          2156:                pf_rtlabel_copyout(&pp->addr.addr);
        !          2157:                break;
        !          2158:        }
        !          2159:
        !          2160:        case DIOCCHANGEADDR: {
        !          2161:                struct pfioc_pooladdr   *pca = (struct pfioc_pooladdr *)addr;
        !          2162:                struct pf_pooladdr      *oldpa = NULL, *newpa = NULL;
        !          2163:                struct pf_ruleset       *ruleset;
        !          2164:
        !          2165:                if (pca->action < PF_CHANGE_ADD_HEAD ||
        !          2166:                    pca->action > PF_CHANGE_REMOVE) {
        !          2167:                        error = EINVAL;
        !          2168:                        break;
        !          2169:                }
        !          2170:                if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
        !          2171:                    pca->addr.addr.type != PF_ADDR_DYNIFTL &&
        !          2172:                    pca->addr.addr.type != PF_ADDR_TABLE) {
        !          2173:                        error = EINVAL;
        !          2174:                        break;
        !          2175:                }
        !          2176:
        !          2177:                ruleset = pf_find_ruleset(pca->anchor);
        !          2178:                if (ruleset == NULL) {
        !          2179:                        error = EBUSY;
        !          2180:                        break;
        !          2181:                }
        !          2182:                pool = pf_get_pool(pca->anchor, pca->ticket, pca->r_action,
        !          2183:                    pca->r_num, pca->r_last, 1, 1);
        !          2184:                if (pool == NULL) {
        !          2185:                        error = EBUSY;
        !          2186:                        break;
        !          2187:                }
        !          2188:                if (pca->action != PF_CHANGE_REMOVE) {
        !          2189:                        newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
        !          2190:                        if (newpa == NULL) {
        !          2191:                                error = ENOMEM;
        !          2192:                                break;
        !          2193:                        }
        !          2194:                        bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr));
        !          2195: #ifndef INET
        !          2196:                        if (pca->af == AF_INET) {
        !          2197:                                pool_put(&pf_pooladdr_pl, newpa);
        !          2198:                                error = EAFNOSUPPORT;
        !          2199:                                break;
        !          2200:                        }
        !          2201: #endif /* INET */
        !          2202: #ifndef INET6
        !          2203:                        if (pca->af == AF_INET6) {
        !          2204:                                pool_put(&pf_pooladdr_pl, newpa);
        !          2205:                                error = EAFNOSUPPORT;
        !          2206:                                break;
        !          2207:                        }
        !          2208: #endif /* INET6 */
        !          2209:                        if (newpa->ifname[0]) {
        !          2210:                                newpa->kif = pfi_kif_get(newpa->ifname);
        !          2211:                                if (newpa->kif == NULL) {
        !          2212:                                        pool_put(&pf_pooladdr_pl, newpa);
        !          2213:                                        error = EINVAL;
        !          2214:                                        break;
        !          2215:                                }
        !          2216:                                pfi_kif_ref(newpa->kif, PFI_KIF_REF_RULE);
        !          2217:                        } else
        !          2218:                                newpa->kif = NULL;
        !          2219:                        if (pfi_dynaddr_setup(&newpa->addr, pca->af) ||
        !          2220:                            pf_tbladdr_setup(ruleset, &newpa->addr)) {
        !          2221:                                pfi_dynaddr_remove(&newpa->addr);
        !          2222:                                pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE);
        !          2223:                                pool_put(&pf_pooladdr_pl, newpa);
        !          2224:                                error = EINVAL;
        !          2225:                                break;
        !          2226:                        }
        !          2227:                }
        !          2228:
        !          2229:                if (pca->action == PF_CHANGE_ADD_HEAD)
        !          2230:                        oldpa = TAILQ_FIRST(&pool->list);
        !          2231:                else if (pca->action == PF_CHANGE_ADD_TAIL)
        !          2232:                        oldpa = TAILQ_LAST(&pool->list, pf_palist);
        !          2233:                else {
        !          2234:                        int     i = 0;
        !          2235:
        !          2236:                        oldpa = TAILQ_FIRST(&pool->list);
        !          2237:                        while ((oldpa != NULL) && (i < pca->nr)) {
        !          2238:                                oldpa = TAILQ_NEXT(oldpa, entries);
        !          2239:                                i++;
        !          2240:                        }
        !          2241:                        if (oldpa == NULL) {
        !          2242:                                error = EINVAL;
        !          2243:                                break;
        !          2244:                        }
        !          2245:                }
        !          2246:
        !          2247:                if (pca->action == PF_CHANGE_REMOVE) {
        !          2248:                        TAILQ_REMOVE(&pool->list, oldpa, entries);
        !          2249:                        pfi_dynaddr_remove(&oldpa->addr);
        !          2250:                        pf_tbladdr_remove(&oldpa->addr);
        !          2251:                        pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE);
        !          2252:                        pool_put(&pf_pooladdr_pl, oldpa);
        !          2253:                } else {
        !          2254:                        if (oldpa == NULL)
        !          2255:                                TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
        !          2256:                        else if (pca->action == PF_CHANGE_ADD_HEAD ||
        !          2257:                            pca->action == PF_CHANGE_ADD_BEFORE)
        !          2258:                                TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
        !          2259:                        else
        !          2260:                                TAILQ_INSERT_AFTER(&pool->list, oldpa,
        !          2261:                                    newpa, entries);
        !          2262:                }
        !          2263:
        !          2264:                pool->cur = TAILQ_FIRST(&pool->list);
        !          2265:                PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr,
        !          2266:                    pca->af);
        !          2267:                break;
        !          2268:        }
        !          2269:
        !          2270:        case DIOCGETRULESETS: {
        !          2271:                struct pfioc_ruleset    *pr = (struct pfioc_ruleset *)addr;
        !          2272:                struct pf_ruleset       *ruleset;
        !          2273:                struct pf_anchor        *anchor;
        !          2274:
        !          2275:                pr->path[sizeof(pr->path) - 1] = 0;
        !          2276:                if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
        !          2277:                        error = EINVAL;
        !          2278:                        break;
        !          2279:                }
        !          2280:                pr->nr = 0;
        !          2281:                if (ruleset->anchor == NULL) {
        !          2282:                        /* XXX kludge for pf_main_ruleset */
        !          2283:                        RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
        !          2284:                                if (anchor->parent == NULL)
        !          2285:                                        pr->nr++;
        !          2286:                } else {
        !          2287:                        RB_FOREACH(anchor, pf_anchor_node,
        !          2288:                            &ruleset->anchor->children)
        !          2289:                                pr->nr++;
        !          2290:                }
        !          2291:                break;
        !          2292:        }
        !          2293:
        !          2294:        case DIOCGETRULESET: {
        !          2295:                struct pfioc_ruleset    *pr = (struct pfioc_ruleset *)addr;
        !          2296:                struct pf_ruleset       *ruleset;
        !          2297:                struct pf_anchor        *anchor;
        !          2298:                u_int32_t                nr = 0;
        !          2299:
        !          2300:                pr->path[sizeof(pr->path) - 1] = 0;
        !          2301:                if ((ruleset = pf_find_ruleset(pr->path)) == NULL) {
        !          2302:                        error = EINVAL;
        !          2303:                        break;
        !          2304:                }
        !          2305:                pr->name[0] = 0;
        !          2306:                if (ruleset->anchor == NULL) {
        !          2307:                        /* XXX kludge for pf_main_ruleset */
        !          2308:                        RB_FOREACH(anchor, pf_anchor_global, &pf_anchors)
        !          2309:                                if (anchor->parent == NULL && nr++ == pr->nr) {
        !          2310:                                        strlcpy(pr->name, anchor->name,
        !          2311:                                            sizeof(pr->name));
        !          2312:                                        break;
        !          2313:                                }
        !          2314:                } else {
        !          2315:                        RB_FOREACH(anchor, pf_anchor_node,
        !          2316:                            &ruleset->anchor->children)
        !          2317:                                if (nr++ == pr->nr) {
        !          2318:                                        strlcpy(pr->name, anchor->name,
        !          2319:                                            sizeof(pr->name));
        !          2320:                                        break;
        !          2321:                                }
        !          2322:                }
        !          2323:                if (!pr->name[0])
        !          2324:                        error = EBUSY;
        !          2325:                break;
        !          2326:        }
        !          2327:
        !          2328:        case DIOCRCLRTABLES: {
        !          2329:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2330:
        !          2331:                if (io->pfrio_esize != 0) {
        !          2332:                        error = ENODEV;
        !          2333:                        break;
        !          2334:                }
        !          2335:                error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
        !          2336:                    io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2337:                break;
        !          2338:        }
        !          2339:
        !          2340:        case DIOCRADDTABLES: {
        !          2341:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2342:
        !          2343:                if (io->pfrio_esize != sizeof(struct pfr_table)) {
        !          2344:                        error = ENODEV;
        !          2345:                        break;
        !          2346:                }
        !          2347:                error = pfr_add_tables(io->pfrio_buffer, io->pfrio_size,
        !          2348:                    &io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2349:                break;
        !          2350:        }
        !          2351:
        !          2352:        case DIOCRDELTABLES: {
        !          2353:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2354:
        !          2355:                if (io->pfrio_esize != sizeof(struct pfr_table)) {
        !          2356:                        error = ENODEV;
        !          2357:                        break;
        !          2358:                }
        !          2359:                error = pfr_del_tables(io->pfrio_buffer, io->pfrio_size,
        !          2360:                    &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2361:                break;
        !          2362:        }
        !          2363:
        !          2364:        case DIOCRGETTABLES: {
        !          2365:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2366:
        !          2367:                if (io->pfrio_esize != sizeof(struct pfr_table)) {
        !          2368:                        error = ENODEV;
        !          2369:                        break;
        !          2370:                }
        !          2371:                error = pfr_get_tables(&io->pfrio_table, io->pfrio_buffer,
        !          2372:                    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2373:                break;
        !          2374:        }
        !          2375:
        !          2376:        case DIOCRGETTSTATS: {
        !          2377:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2378:
        !          2379:                if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
        !          2380:                        error = ENODEV;
        !          2381:                        break;
        !          2382:                }
        !          2383:                error = pfr_get_tstats(&io->pfrio_table, io->pfrio_buffer,
        !          2384:                    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2385:                break;
        !          2386:        }
        !          2387:
        !          2388:        case DIOCRCLRTSTATS: {
        !          2389:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2390:
        !          2391:                if (io->pfrio_esize != sizeof(struct pfr_table)) {
        !          2392:                        error = ENODEV;
        !          2393:                        break;
        !          2394:                }
        !          2395:                error = pfr_clr_tstats(io->pfrio_buffer, io->pfrio_size,
        !          2396:                    &io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2397:                break;
        !          2398:        }
        !          2399:
        !          2400:        case DIOCRSETTFLAGS: {
        !          2401:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2402:
        !          2403:                if (io->pfrio_esize != sizeof(struct pfr_table)) {
        !          2404:                        error = ENODEV;
        !          2405:                        break;
        !          2406:                }
        !          2407:                error = pfr_set_tflags(io->pfrio_buffer, io->pfrio_size,
        !          2408:                    io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
        !          2409:                    &io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2410:                break;
        !          2411:        }
        !          2412:
        !          2413:        case DIOCRCLRADDRS: {
        !          2414:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2415:
        !          2416:                if (io->pfrio_esize != 0) {
        !          2417:                        error = ENODEV;
        !          2418:                        break;
        !          2419:                }
        !          2420:                error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
        !          2421:                    io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2422:                break;
        !          2423:        }
        !          2424:
        !          2425:        case DIOCRADDADDRS: {
        !          2426:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2427:
        !          2428:                if (io->pfrio_esize != sizeof(struct pfr_addr)) {
        !          2429:                        error = ENODEV;
        !          2430:                        break;
        !          2431:                }
        !          2432:                error = pfr_add_addrs(&io->pfrio_table, io->pfrio_buffer,
        !          2433:                    io->pfrio_size, &io->pfrio_nadd, io->pfrio_flags |
        !          2434:                    PFR_FLAG_USERIOCTL);
        !          2435:                break;
        !          2436:        }
        !          2437:
        !          2438:        case DIOCRDELADDRS: {
        !          2439:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2440:
        !          2441:                if (io->pfrio_esize != sizeof(struct pfr_addr)) {
        !          2442:                        error = ENODEV;
        !          2443:                        break;
        !          2444:                }
        !          2445:                error = pfr_del_addrs(&io->pfrio_table, io->pfrio_buffer,
        !          2446:                    io->pfrio_size, &io->pfrio_ndel, io->pfrio_flags |
        !          2447:                    PFR_FLAG_USERIOCTL);
        !          2448:                break;
        !          2449:        }
        !          2450:
        !          2451:        case DIOCRSETADDRS: {
        !          2452:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2453:
        !          2454:                if (io->pfrio_esize != sizeof(struct pfr_addr)) {
        !          2455:                        error = ENODEV;
        !          2456:                        break;
        !          2457:                }
        !          2458:                error = pfr_set_addrs(&io->pfrio_table, io->pfrio_buffer,
        !          2459:                    io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,
        !          2460:                    &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags |
        !          2461:                    PFR_FLAG_USERIOCTL, 0);
        !          2462:                break;
        !          2463:        }
        !          2464:
        !          2465:        case DIOCRGETADDRS: {
        !          2466:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2467:
        !          2468:                if (io->pfrio_esize != sizeof(struct pfr_addr)) {
        !          2469:                        error = ENODEV;
        !          2470:                        break;
        !          2471:                }
        !          2472:                error = pfr_get_addrs(&io->pfrio_table, io->pfrio_buffer,
        !          2473:                    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2474:                break;
        !          2475:        }
        !          2476:
        !          2477:        case DIOCRGETASTATS: {
        !          2478:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2479:
        !          2480:                if (io->pfrio_esize != sizeof(struct pfr_astats)) {
        !          2481:                        error = ENODEV;
        !          2482:                        break;
        !          2483:                }
        !          2484:                error = pfr_get_astats(&io->pfrio_table, io->pfrio_buffer,
        !          2485:                    &io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2486:                break;
        !          2487:        }
        !          2488:
        !          2489:        case DIOCRCLRASTATS: {
        !          2490:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2491:
        !          2492:                if (io->pfrio_esize != sizeof(struct pfr_addr)) {
        !          2493:                        error = ENODEV;
        !          2494:                        break;
        !          2495:                }
        !          2496:                error = pfr_clr_astats(&io->pfrio_table, io->pfrio_buffer,
        !          2497:                    io->pfrio_size, &io->pfrio_nzero, io->pfrio_flags |
        !          2498:                    PFR_FLAG_USERIOCTL);
        !          2499:                break;
        !          2500:        }
        !          2501:
        !          2502:        case DIOCRTSTADDRS: {
        !          2503:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2504:
        !          2505:                if (io->pfrio_esize != sizeof(struct pfr_addr)) {
        !          2506:                        error = ENODEV;
        !          2507:                        break;
        !          2508:                }
        !          2509:                error = pfr_tst_addrs(&io->pfrio_table, io->pfrio_buffer,
        !          2510:                    io->pfrio_size, &io->pfrio_nmatch, io->pfrio_flags |
        !          2511:                    PFR_FLAG_USERIOCTL);
        !          2512:                break;
        !          2513:        }
        !          2514:
        !          2515:        case DIOCRINADEFINE: {
        !          2516:                struct pfioc_table *io = (struct pfioc_table *)addr;
        !          2517:
        !          2518:                if (io->pfrio_esize != sizeof(struct pfr_addr)) {
        !          2519:                        error = ENODEV;
        !          2520:                        break;
        !          2521:                }
        !          2522:                error = pfr_ina_define(&io->pfrio_table, io->pfrio_buffer,
        !          2523:                    io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
        !          2524:                    io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL);
        !          2525:                break;
        !          2526:        }
        !          2527:
        !          2528:        case DIOCOSFPADD: {
        !          2529:                struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
        !          2530:                error = pf_osfp_add(io);
        !          2531:                break;
        !          2532:        }
        !          2533:
        !          2534:        case DIOCOSFPGET: {
        !          2535:                struct pf_osfp_ioctl *io = (struct pf_osfp_ioctl *)addr;
        !          2536:                error = pf_osfp_get(io);
        !          2537:                break;
        !          2538:        }
        !          2539:
        !          2540:        case DIOCXBEGIN: {
        !          2541:                struct pfioc_trans      *io = (struct pfioc_trans *)addr;
        !          2542:                struct pfioc_trans_e    *ioe;
        !          2543:                struct pfr_table        *table;
        !          2544:                int                      i;
        !          2545:
        !          2546:                if (io->esize != sizeof(*ioe)) {
        !          2547:                        error = ENODEV;
        !          2548:                        goto fail;
        !          2549:                }
        !          2550:                ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
        !          2551:                    M_TEMP, M_WAITOK);
        !          2552:                table = (struct pfr_table *)malloc(sizeof(*table),
        !          2553:                    M_TEMP, M_WAITOK);
        !          2554:                for (i = 0; i < io->size; i++) {
        !          2555:                        if (copyin(io->array+i, ioe, sizeof(*ioe))) {
        !          2556:                                free(table, M_TEMP);
        !          2557:                                free(ioe, M_TEMP);
        !          2558:                                error = EFAULT;
        !          2559:                                goto fail;
        !          2560:                        }
        !          2561:                        switch (ioe->rs_num) {
        !          2562: #ifdef ALTQ
        !          2563:                        case PF_RULESET_ALTQ:
        !          2564:                                if (ioe->anchor[0]) {
        !          2565:                                        free(table, M_TEMP);
        !          2566:                                        free(ioe, M_TEMP);
        !          2567:                                        error = EINVAL;
        !          2568:                                        goto fail;
        !          2569:                                }
        !          2570:                                if ((error = pf_begin_altq(&ioe->ticket))) {
        !          2571:                                        free(table, M_TEMP);
        !          2572:                                        free(ioe, M_TEMP);
        !          2573:                                        goto fail;
        !          2574:                                }
        !          2575:                                break;
        !          2576: #endif /* ALTQ */
        !          2577:                        case PF_RULESET_TABLE:
        !          2578:                                bzero(table, sizeof(*table));
        !          2579:                                strlcpy(table->pfrt_anchor, ioe->anchor,
        !          2580:                                    sizeof(table->pfrt_anchor));
        !          2581:                                if ((error = pfr_ina_begin(table,
        !          2582:                                    &ioe->ticket, NULL, 0))) {
        !          2583:                                        free(table, M_TEMP);
        !          2584:                                        free(ioe, M_TEMP);
        !          2585:                                        goto fail;
        !          2586:                                }
        !          2587:                                break;
        !          2588:                        default:
        !          2589:                                if ((error = pf_begin_rules(&ioe->ticket,
        !          2590:                                    ioe->rs_num, ioe->anchor))) {
        !          2591:                                        free(table, M_TEMP);
        !          2592:                                        free(ioe, M_TEMP);
        !          2593:                                        goto fail;
        !          2594:                                }
        !          2595:                                break;
        !          2596:                        }
        !          2597:                        if (copyout(ioe, io->array+i, sizeof(io->array[i]))) {
        !          2598:                                free(table, M_TEMP);
        !          2599:                                free(ioe, M_TEMP);
        !          2600:                                error = EFAULT;
        !          2601:                                goto fail;
        !          2602:                        }
        !          2603:                }
        !          2604:                free(table, M_TEMP);
        !          2605:                free(ioe, M_TEMP);
        !          2606:                break;
        !          2607:        }
        !          2608:
        !          2609:        case DIOCXROLLBACK: {
        !          2610:                struct pfioc_trans      *io = (struct pfioc_trans *)addr;
        !          2611:                struct pfioc_trans_e    *ioe;
        !          2612:                struct pfr_table        *table;
        !          2613:                int                      i;
        !          2614:
        !          2615:                if (io->esize != sizeof(*ioe)) {
        !          2616:                        error = ENODEV;
        !          2617:                        goto fail;
        !          2618:                }
        !          2619:                ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
        !          2620:                    M_TEMP, M_WAITOK);
        !          2621:                table = (struct pfr_table *)malloc(sizeof(*table),
        !          2622:                    M_TEMP, M_WAITOK);
        !          2623:                for (i = 0; i < io->size; i++) {
        !          2624:                        if (copyin(io->array+i, ioe, sizeof(*ioe))) {
        !          2625:                                free(table, M_TEMP);
        !          2626:                                free(ioe, M_TEMP);
        !          2627:                                error = EFAULT;
        !          2628:                                goto fail;
        !          2629:                        }
        !          2630:                        switch (ioe->rs_num) {
        !          2631: #ifdef ALTQ
        !          2632:                        case PF_RULESET_ALTQ:
        !          2633:                                if (ioe->anchor[0]) {
        !          2634:                                        free(table, M_TEMP);
        !          2635:                                        free(ioe, M_TEMP);
        !          2636:                                        error = EINVAL;
        !          2637:                                        goto fail;
        !          2638:                                }
        !          2639:                                if ((error = pf_rollback_altq(ioe->ticket))) {
        !          2640:                                        free(table, M_TEMP);
        !          2641:                                        free(ioe, M_TEMP);
        !          2642:                                        goto fail; /* really bad */
        !          2643:                                }
        !          2644:                                break;
        !          2645: #endif /* ALTQ */
        !          2646:                        case PF_RULESET_TABLE:
        !          2647:                                bzero(table, sizeof(*table));
        !          2648:                                strlcpy(table->pfrt_anchor, ioe->anchor,
        !          2649:                                    sizeof(table->pfrt_anchor));
        !          2650:                                if ((error = pfr_ina_rollback(table,
        !          2651:                                    ioe->ticket, NULL, 0))) {
        !          2652:                                        free(table, M_TEMP);
        !          2653:                                        free(ioe, M_TEMP);
        !          2654:                                        goto fail; /* really bad */
        !          2655:                                }
        !          2656:                                break;
        !          2657:                        default:
        !          2658:                                if ((error = pf_rollback_rules(ioe->ticket,
        !          2659:                                    ioe->rs_num, ioe->anchor))) {
        !          2660:                                        free(table, M_TEMP);
        !          2661:                                        free(ioe, M_TEMP);
        !          2662:                                        goto fail; /* really bad */
        !          2663:                                }
        !          2664:                                break;
        !          2665:                        }
        !          2666:                }
        !          2667:                free(table, M_TEMP);
        !          2668:                free(ioe, M_TEMP);
        !          2669:                break;
        !          2670:        }
        !          2671:
        !          2672:        case DIOCXCOMMIT: {
        !          2673:                struct pfioc_trans      *io = (struct pfioc_trans *)addr;
        !          2674:                struct pfioc_trans_e    *ioe;
        !          2675:                struct pfr_table        *table;
        !          2676:                struct pf_ruleset       *rs;
        !          2677:                int                      i;
        !          2678:
        !          2679:                if (io->esize != sizeof(*ioe)) {
        !          2680:                        error = ENODEV;
        !          2681:                        goto fail;
        !          2682:                }
        !          2683:                ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe),
        !          2684:                    M_TEMP, M_WAITOK);
        !          2685:                table = (struct pfr_table *)malloc(sizeof(*table),
        !          2686:                    M_TEMP, M_WAITOK);
        !          2687:                /* first makes sure everything will succeed */
        !          2688:                for (i = 0; i < io->size; i++) {
        !          2689:                        if (copyin(io->array+i, ioe, sizeof(*ioe))) {
        !          2690:                                free(table, M_TEMP);
        !          2691:                                free(ioe, M_TEMP);
        !          2692:                                error = EFAULT;
        !          2693:                                goto fail;
        !          2694:                        }
        !          2695:                        switch (ioe->rs_num) {
        !          2696: #ifdef ALTQ
        !          2697:                        case PF_RULESET_ALTQ:
        !          2698:                                if (ioe->anchor[0]) {
        !          2699:                                        free(table, M_TEMP);
        !          2700:                                        free(ioe, M_TEMP);
        !          2701:                                        error = EINVAL;
        !          2702:                                        goto fail;
        !          2703:                                }
        !          2704:                                if (!altqs_inactive_open || ioe->ticket !=
        !          2705:                                    ticket_altqs_inactive) {
        !          2706:                                        free(table, M_TEMP);
        !          2707:                                        free(ioe, M_TEMP);
        !          2708:                                        error = EBUSY;
        !          2709:                                        goto fail;
        !          2710:                                }
        !          2711:                                break;
        !          2712: #endif /* ALTQ */
        !          2713:                        case PF_RULESET_TABLE:
        !          2714:                                rs = pf_find_ruleset(ioe->anchor);
        !          2715:                                if (rs == NULL || !rs->topen || ioe->ticket !=
        !          2716:                                     rs->tticket) {
        !          2717:                                        free(table, M_TEMP);
        !          2718:                                        free(ioe, M_TEMP);
        !          2719:                                        error = EBUSY;
        !          2720:                                        goto fail;
        !          2721:                                }
        !          2722:                                break;
        !          2723:                        default:
        !          2724:                                if (ioe->rs_num < 0 || ioe->rs_num >=
        !          2725:                                    PF_RULESET_MAX) {
        !          2726:                                        free(table, M_TEMP);
        !          2727:                                        free(ioe, M_TEMP);
        !          2728:                                        error = EINVAL;
        !          2729:                                        goto fail;
        !          2730:                                }
        !          2731:                                rs = pf_find_ruleset(ioe->anchor);
        !          2732:                                if (rs == NULL ||
        !          2733:                                    !rs->rules[ioe->rs_num].inactive.open ||
        !          2734:                                    rs->rules[ioe->rs_num].inactive.ticket !=
        !          2735:                                    ioe->ticket) {
        !          2736:                                        free(table, M_TEMP);
        !          2737:                                        free(ioe, M_TEMP);
        !          2738:                                        error = EBUSY;
        !          2739:                                        goto fail;
        !          2740:                                }
        !          2741:                                break;
        !          2742:                        }
        !          2743:                }
        !          2744:                /* now do the commit - no errors should happen here */
        !          2745:                for (i = 0; i < io->size; i++) {
        !          2746:                        if (copyin(io->array+i, ioe, sizeof(*ioe))) {
        !          2747:                                free(table, M_TEMP);
        !          2748:                                free(ioe, M_TEMP);
        !          2749:                                error = EFAULT;
        !          2750:                                goto fail;
        !          2751:                        }
        !          2752:                        switch (ioe->rs_num) {
        !          2753: #ifdef ALTQ
        !          2754:                        case PF_RULESET_ALTQ:
        !          2755:                                if ((error = pf_commit_altq(ioe->ticket))) {
        !          2756:                                        free(table, M_TEMP);
        !          2757:                                        free(ioe, M_TEMP);
        !          2758:                                        goto fail; /* really bad */
        !          2759:                                }
        !          2760:                                break;
        !          2761: #endif /* ALTQ */
        !          2762:                        case PF_RULESET_TABLE:
        !          2763:                                bzero(table, sizeof(*table));
        !          2764:                                strlcpy(table->pfrt_anchor, ioe->anchor,
        !          2765:                                    sizeof(table->pfrt_anchor));
        !          2766:                                if ((error = pfr_ina_commit(table, ioe->ticket,
        !          2767:                                    NULL, NULL, 0))) {
        !          2768:                                        free(table, M_TEMP);
        !          2769:                                        free(ioe, M_TEMP);
        !          2770:                                        goto fail; /* really bad */
        !          2771:                                }
        !          2772:                                break;
        !          2773:                        default:
        !          2774:                                if ((error = pf_commit_rules(ioe->ticket,
        !          2775:                                    ioe->rs_num, ioe->anchor))) {
        !          2776:                                        free(table, M_TEMP);
        !          2777:                                        free(ioe, M_TEMP);
        !          2778:                                        goto fail; /* really bad */
        !          2779:                                }
        !          2780:                                break;
        !          2781:                        }
        !          2782:                }
        !          2783:                free(table, M_TEMP);
        !          2784:                free(ioe, M_TEMP);
        !          2785:                break;
        !          2786:        }
        !          2787:
        !          2788:        case DIOCGETSRCNODES: {
        !          2789:                struct pfioc_src_nodes  *psn = (struct pfioc_src_nodes *)addr;
        !          2790:                struct pf_src_node      *n, *p, *pstore;
        !          2791:                u_int32_t                nr = 0;
        !          2792:                int                      space = psn->psn_len;
        !          2793:
        !          2794:                if (space == 0) {
        !          2795:                        RB_FOREACH(n, pf_src_tree, &tree_src_tracking)
        !          2796:                                nr++;
        !          2797:                        psn->psn_len = sizeof(struct pf_src_node) * nr;
        !          2798:                        break;
        !          2799:                }
        !          2800:
        !          2801:                pstore = malloc(sizeof(*pstore), M_TEMP, M_WAITOK);
        !          2802:
        !          2803:                p = psn->psn_src_nodes;
        !          2804:                RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
        !          2805:                        int     secs = time_second, diff;
        !          2806:
        !          2807:                        if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len)
        !          2808:                                break;
        !          2809:
        !          2810:                        bcopy(n, pstore, sizeof(*pstore));
        !          2811:                        if (n->rule.ptr != NULL)
        !          2812:                                pstore->rule.nr = n->rule.ptr->nr;
        !          2813:                        pstore->creation = secs - pstore->creation;
        !          2814:                        if (pstore->expire > secs)
        !          2815:                                pstore->expire -= secs;
        !          2816:                        else
        !          2817:                                pstore->expire = 0;
        !          2818:
        !          2819:                        /* adjust the connection rate estimate */
        !          2820:                        diff = secs - n->conn_rate.last;
        !          2821:                        if (diff >= n->conn_rate.seconds)
        !          2822:                                pstore->conn_rate.count = 0;
        !          2823:                        else
        !          2824:                                pstore->conn_rate.count -=
        !          2825:                                    n->conn_rate.count * diff /
        !          2826:                                    n->conn_rate.seconds;
        !          2827:
        !          2828:                        error = copyout(pstore, p, sizeof(*p));
        !          2829:                        if (error) {
        !          2830:                                free(pstore, M_TEMP);
        !          2831:                                goto fail;
        !          2832:                        }
        !          2833:                        p++;
        !          2834:                        nr++;
        !          2835:                }
        !          2836:                psn->psn_len = sizeof(struct pf_src_node) * nr;
        !          2837:
        !          2838:                free(pstore, M_TEMP);
        !          2839:                break;
        !          2840:        }
        !          2841:
        !          2842:        case DIOCCLRSRCNODES: {
        !          2843:                struct pf_src_node      *n;
        !          2844:                struct pf_state         *state;
        !          2845:
        !          2846:                RB_FOREACH(state, pf_state_tree_id, &tree_id) {
        !          2847:                        state->src_node = NULL;
        !          2848:                        state->nat_src_node = NULL;
        !          2849:                }
        !          2850:                RB_FOREACH(n, pf_src_tree, &tree_src_tracking) {
        !          2851:                        n->expire = 1;
        !          2852:                        n->states = 0;
        !          2853:                }
        !          2854:                pf_purge_expired_src_nodes(1);
        !          2855:                pf_status.src_nodes = 0;
        !          2856:                break;
        !          2857:        }
        !          2858:
        !          2859:        case DIOCKILLSRCNODES: {
        !          2860:                struct pf_src_node      *sn;
        !          2861:                struct pf_state         *s;
        !          2862:                struct pfioc_src_node_kill *psnk = \
        !          2863:                        (struct pfioc_src_node_kill *) addr;
        !          2864:                int                     killed = 0;
        !          2865:
        !          2866:                RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) {
        !          2867:                        if (PF_MATCHA(psnk->psnk_src.neg, \
        !          2868:                                      &psnk->psnk_src.addr.v.a.addr, \
        !          2869:                                      &psnk->psnk_src.addr.v.a.mask, \
        !          2870:                                      &sn->addr, sn->af) &&
        !          2871:                            PF_MATCHA(psnk->psnk_dst.neg, \
        !          2872:                                      &psnk->psnk_dst.addr.v.a.addr, \
        !          2873:                                      &psnk->psnk_dst.addr.v.a.mask, \
        !          2874:                                      &sn->raddr, sn->af)) {
        !          2875:                                /* Handle state to src_node linkage */
        !          2876:                                if (sn->states != 0) {
        !          2877:                                        RB_FOREACH(s, pf_state_tree_id,
        !          2878:                                            &tree_id) {
        !          2879:                                                if (s->src_node == sn)
        !          2880:                                                        s->src_node = NULL;
        !          2881:                                                if (s->nat_src_node == sn)
        !          2882:                                                        s->nat_src_node = NULL;
        !          2883:                                        }
        !          2884:                                        sn->states = 0;
        !          2885:                                }
        !          2886:                                sn->expire = 1;
        !          2887:                                killed++;
        !          2888:                        }
        !          2889:                }
        !          2890:
        !          2891:                if (killed > 0)
        !          2892:                        pf_purge_expired_src_nodes(1);
        !          2893:
        !          2894:                psnk->psnk_af = killed;
        !          2895:                break;
        !          2896:        }
        !          2897:
        !          2898:        case DIOCSETHOSTID: {
        !          2899:                u_int32_t       *hostid = (u_int32_t *)addr;
        !          2900:
        !          2901:                if (*hostid == 0)
        !          2902:                        pf_status.hostid = arc4random();
        !          2903:                else
        !          2904:                        pf_status.hostid = *hostid;
        !          2905:                break;
        !          2906:        }
        !          2907:
        !          2908:        case DIOCOSFPFLUSH:
        !          2909:                pf_osfp_flush();
        !          2910:                break;
        !          2911:
        !          2912:        case DIOCIGETIFACES: {
        !          2913:                struct pfioc_iface *io = (struct pfioc_iface *)addr;
        !          2914:
        !          2915:                if (io->pfiio_esize != sizeof(struct pfi_kif)) {
        !          2916:                        error = ENODEV;
        !          2917:                        break;
        !          2918:                }
        !          2919:                error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer,
        !          2920:                    &io->pfiio_size);
        !          2921:                break;
        !          2922:        }
        !          2923:
        !          2924:        case DIOCSETIFFLAG: {
        !          2925:                struct pfioc_iface *io = (struct pfioc_iface *)addr;
        !          2926:
        !          2927:                error = pfi_set_flags(io->pfiio_name, io->pfiio_flags);
        !          2928:                break;
        !          2929:        }
        !          2930:
        !          2931:        case DIOCCLRIFFLAG: {
        !          2932:                struct pfioc_iface *io = (struct pfioc_iface *)addr;
        !          2933:
        !          2934:                error = pfi_clear_flags(io->pfiio_name, io->pfiio_flags);
        !          2935:                break;
        !          2936:        }
        !          2937:
        !          2938:        default:
        !          2939:                error = ENODEV;
        !          2940:                break;
        !          2941:        }
        !          2942: fail:
        !          2943:        splx(s);
        !          2944:        if (flags & FWRITE)
        !          2945:                rw_exit_write(&pf_consistency_lock);
        !          2946:        else
        !          2947:                rw_exit_read(&pf_consistency_lock);
        !          2948:        return (error);
        !          2949: }

CVSweb