13b3a8eb9SGleb Smirnoff /*- 23b3a8eb9SGleb Smirnoff * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. 33b3a8eb9SGleb Smirnoff * 43b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 53b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions 63b3a8eb9SGleb Smirnoff * are met: 73b3a8eb9SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 83b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 93b3a8eb9SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 103b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 113b3a8eb9SGleb Smirnoff * documentation and/or other materials provided with the distribution. 123b3a8eb9SGleb Smirnoff * 133b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 143b3a8eb9SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 153b3a8eb9SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 163b3a8eb9SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 173b3a8eb9SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 183b3a8eb9SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 193b3a8eb9SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 203b3a8eb9SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 213b3a8eb9SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 223b3a8eb9SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 233b3a8eb9SGleb Smirnoff * SUCH DAMAGE. 243b3a8eb9SGleb Smirnoff */ 253b3a8eb9SGleb Smirnoff 263b3a8eb9SGleb Smirnoff #include <sys/cdefs.h> 273b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$"); 283b3a8eb9SGleb Smirnoff 293b3a8eb9SGleb Smirnoff /* 30563b5ab1SAlexander V. Chernikov * Lookup table support for ipfw. 313b3a8eb9SGleb Smirnoff * 32ac35ff17SAlexander V. Chernikov * This file contains handlers for all generic tables' operations: 33563b5ab1SAlexander V. Chernikov * add/del/flush entries, list/dump tables etc.. 343b3a8eb9SGleb Smirnoff * 35563b5ab1SAlexander V. Chernikov * Table data modification is protected by both UH and runtimg lock 36563b5ab1SAlexander V. Chernikov * while reading configuration/data is protected by UH lock. 37563b5ab1SAlexander V. Chernikov * 38563b5ab1SAlexander V. Chernikov * Lookup algorithms for all table types are located in ip_fw_table_algo.c 393b3a8eb9SGleb Smirnoff */ 403b3a8eb9SGleb Smirnoff 413b3a8eb9SGleb Smirnoff #include "opt_ipfw.h" 423b3a8eb9SGleb Smirnoff 433b3a8eb9SGleb Smirnoff #include <sys/param.h> 443b3a8eb9SGleb Smirnoff #include <sys/systm.h> 453b3a8eb9SGleb Smirnoff #include <sys/malloc.h> 463b3a8eb9SGleb Smirnoff #include <sys/kernel.h> 473b3a8eb9SGleb Smirnoff #include <sys/lock.h> 483b3a8eb9SGleb Smirnoff #include <sys/rwlock.h> 493b3a8eb9SGleb Smirnoff #include <sys/socket.h> 50f1220db8SAlexander V. Chernikov #include <sys/socketvar.h> 513b3a8eb9SGleb Smirnoff #include <sys/queue.h> 523b3a8eb9SGleb Smirnoff #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 533b3a8eb9SGleb Smirnoff #include <net/route.h> 543b3a8eb9SGleb Smirnoff #include <net/vnet.h> 553b3a8eb9SGleb Smirnoff 563b3a8eb9SGleb Smirnoff #include <netinet/in.h> 573b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 583b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h> 593b3a8eb9SGleb Smirnoff 603b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h> 61ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 623b3a8eb9SGleb Smirnoff 633b3a8eb9SGleb Smirnoff 643b3a8eb9SGleb Smirnoff /* 65b074b7bbSAlexander V. Chernikov * Table has the following `type` concepts: 66b074b7bbSAlexander V. Chernikov * 679f7d47b0SAlexander V. Chernikov * `no.type` represents lookup key type (cidr, ifp, uid, etc..) 689f7d47b0SAlexander V. Chernikov * `ta->atype` represents exact lookup algorithm. 69b074b7bbSAlexander V. Chernikov * For example, we can use more efficient search schemes if we plan 70b074b7bbSAlexander V. Chernikov * to use some specific table for storing host-routes only. 719490a627SAlexander V. Chernikov * `ftype` (at the moment )is pure userland field helping to properly 729490a627SAlexander V. Chernikov * format value data e.g. "value is IPv4 nexthop" or "value is DSCP" 739490a627SAlexander V. Chernikov * or "value is port". 74b074b7bbSAlexander V. Chernikov * 75b074b7bbSAlexander V. Chernikov */ 76b074b7bbSAlexander V. Chernikov struct table_config { 77b074b7bbSAlexander V. Chernikov struct named_object no; 78ac35ff17SAlexander V. Chernikov uint8_t vtype; /* format table type */ 79b074b7bbSAlexander V. Chernikov uint8_t linked; /* 1 if already linked */ 80db785d31SAlexander V. Chernikov uint16_t spare; 81b074b7bbSAlexander V. Chernikov uint32_t count; /* Number of records */ 82db785d31SAlexander V. Chernikov uint64_t flags; /* state flags */ 83b074b7bbSAlexander V. Chernikov char tablename[64]; /* table name */ 849f7d47b0SAlexander V. Chernikov struct table_algo *ta; /* Callbacks for given algo */ 859f7d47b0SAlexander V. Chernikov void *astate; /* algorithm state */ 869f7d47b0SAlexander V. Chernikov struct table_info ti; /* data to put to table_info */ 87b074b7bbSAlexander V. Chernikov }; 88b074b7bbSAlexander V. Chernikov 89b074b7bbSAlexander V. Chernikov struct tables_config { 90b074b7bbSAlexander V. Chernikov struct namedobj_instance *namehash; 919f7d47b0SAlexander V. Chernikov int algo_count; 929f7d47b0SAlexander V. Chernikov struct table_algo *algo[256]; 93b074b7bbSAlexander V. Chernikov }; 94b074b7bbSAlexander V. Chernikov 95b074b7bbSAlexander V. Chernikov static struct table_config *find_table(struct namedobj_instance *ni, 96b074b7bbSAlexander V. Chernikov struct tid_info *ti); 9768394ec8SAlexander V. Chernikov static struct table_config *alloc_table_config(struct ip_fw_chain *ch, 98db785d31SAlexander V. Chernikov struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t vtype); 99b074b7bbSAlexander V. Chernikov static void free_table_config(struct namedobj_instance *ni, 100b074b7bbSAlexander V. Chernikov struct table_config *tc); 101db785d31SAlexander V. Chernikov static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, 102db785d31SAlexander V. Chernikov char *aname, uint8_t vtype); 103b074b7bbSAlexander V. Chernikov static void link_table(struct ip_fw_chain *chain, struct table_config *tc); 104b074b7bbSAlexander V. Chernikov static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc); 105b074b7bbSAlexander V. Chernikov static void free_table_state(void **state, void **xstate, uint8_t type); 1062d99a349SAlexander V. Chernikov static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 1072d99a349SAlexander V. Chernikov struct sockopt_data *sd); 108ac35ff17SAlexander V. Chernikov static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 109ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i); 11081d3153dSAlexander V. Chernikov static int dump_table_tentry(void *e, void *arg); 111f1220db8SAlexander V. Chernikov static int dump_table_xentry(void *e, void *arg); 112b074b7bbSAlexander V. Chernikov 1132d99a349SAlexander V. Chernikov static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd); 1142d99a349SAlexander V. Chernikov static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd); 115db785d31SAlexander V. Chernikov static int ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 116ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 117db785d31SAlexander V. Chernikov static int ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 118ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 119ac35ff17SAlexander V. Chernikov 120db785d31SAlexander V. Chernikov static int modify_table(struct ip_fw_chain *ch, struct table_config *tc, 121db785d31SAlexander V. Chernikov struct table_algo *ta, void *ta_buf, uint64_t pflags); 122ac35ff17SAlexander V. Chernikov static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti); 123d3a4f924SAlexander V. Chernikov 1249f7d47b0SAlexander V. Chernikov static struct table_algo *find_table_algo(struct tables_config *tableconf, 1259490a627SAlexander V. Chernikov struct tid_info *ti, char *name); 126b074b7bbSAlexander V. Chernikov 127b074b7bbSAlexander V. Chernikov #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) 128b074b7bbSAlexander V. Chernikov #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) 1299f7d47b0SAlexander V. Chernikov #define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) 130b074b7bbSAlexander V. Chernikov 131b074b7bbSAlexander V. Chernikov 1323b3a8eb9SGleb Smirnoff 1333b3a8eb9SGleb Smirnoff int 1341832a7b3SAlexander V. Chernikov add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 135b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 1363b3a8eb9SGleb Smirnoff { 137db785d31SAlexander V. Chernikov struct table_config *tc; 1389f7d47b0SAlexander V. Chernikov struct table_algo *ta; 139b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 140b074b7bbSAlexander V. Chernikov uint16_t kidx; 1419f7d47b0SAlexander V. Chernikov int error; 142adea6201SAlexander V. Chernikov uint32_t num; 143db785d31SAlexander V. Chernikov uint64_t aflags; 1449f7d47b0SAlexander V. Chernikov char ta_buf[128]; 1453b3a8eb9SGleb Smirnoff 1469f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1479f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1489f7d47b0SAlexander V. Chernikov 1499f7d47b0SAlexander V. Chernikov /* 1509f7d47b0SAlexander V. Chernikov * Find and reference existing table. 1519f7d47b0SAlexander V. Chernikov */ 1529f7d47b0SAlexander V. Chernikov ta = NULL; 1539f7d47b0SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1549f7d47b0SAlexander V. Chernikov /* check table type */ 1559f7d47b0SAlexander V. Chernikov if (tc->no.type != ti->type) { 1569f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1573b3a8eb9SGleb Smirnoff return (EINVAL); 1583b3a8eb9SGleb Smirnoff } 1593b3a8eb9SGleb Smirnoff 1609f7d47b0SAlexander V. Chernikov /* Reference and unlock */ 1619f7d47b0SAlexander V. Chernikov tc->no.refcnt++; 1629f7d47b0SAlexander V. Chernikov ta = tc->ta; 163db785d31SAlexander V. Chernikov aflags = tc->flags; 1649f7d47b0SAlexander V. Chernikov } 1659f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1663b3a8eb9SGleb Smirnoff 167ac35ff17SAlexander V. Chernikov if (tc == NULL) { 168db785d31SAlexander V. Chernikov /* Compability mode: create new table for old clients */ 169db785d31SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_COMPAT) == 0) 170db785d31SAlexander V. Chernikov return (ESRCH); 1713b3a8eb9SGleb Smirnoff 172db785d31SAlexander V. Chernikov error = create_table_internal(ch, ti, NULL, IPFW_VTYPE_U32); 173db785d31SAlexander V. Chernikov 174db785d31SAlexander V. Chernikov if (error != 0) 175db785d31SAlexander V. Chernikov return (error); 176db785d31SAlexander V. Chernikov 177db785d31SAlexander V. Chernikov /* Let's try to find & reference another time */ 178db785d31SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 179db785d31SAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 180db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 181db785d31SAlexander V. Chernikov return (EINVAL); 182db785d31SAlexander V. Chernikov } 183db785d31SAlexander V. Chernikov 184db785d31SAlexander V. Chernikov if (tc->no.type != ti->type) { 185db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 186db785d31SAlexander V. Chernikov return (EINVAL); 187db785d31SAlexander V. Chernikov } 188db785d31SAlexander V. Chernikov 189db785d31SAlexander V. Chernikov /* Reference and unlock */ 190db785d31SAlexander V. Chernikov tc->no.refcnt++; 191db785d31SAlexander V. Chernikov ta = tc->ta; 192db785d31SAlexander V. Chernikov aflags = tc->flags; 193db785d31SAlexander V. Chernikov 194db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 195db785d31SAlexander V. Chernikov } 196db785d31SAlexander V. Chernikov 197db785d31SAlexander V. Chernikov if (aflags != 0) { 198db785d31SAlexander V. Chernikov 199db785d31SAlexander V. Chernikov /* 200db785d31SAlexander V. Chernikov * Previous add/delete call returned non-zero state. 201db785d31SAlexander V. Chernikov * Run appropriate handler. 202db785d31SAlexander V. Chernikov */ 203db785d31SAlexander V. Chernikov error = modify_table(ch, tc, ta, &ta_buf, aflags); 204db785d31SAlexander V. Chernikov if (error != 0) 205db785d31SAlexander V. Chernikov return (error); 2069f7d47b0SAlexander V. Chernikov } 2073b3a8eb9SGleb Smirnoff 2089f7d47b0SAlexander V. Chernikov /* Prepare record (allocate memory) */ 2099f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 21068394ec8SAlexander V. Chernikov error = ta->prepare_add(ch, tei, &ta_buf); 211db785d31SAlexander V. Chernikov if (error != 0) 2129f7d47b0SAlexander V. Chernikov return (error); 2133b3a8eb9SGleb Smirnoff 214b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 2153b3a8eb9SGleb Smirnoff 216b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 2173b3a8eb9SGleb Smirnoff 2189f7d47b0SAlexander V. Chernikov /* Drop reference we've used in first search */ 2199f7d47b0SAlexander V. Chernikov tc->no.refcnt--; 220db785d31SAlexander V. Chernikov /* Update aflags since it can be changed after previous read */ 221db785d31SAlexander V. Chernikov aflags = tc->flags; 222b074b7bbSAlexander V. Chernikov 223b074b7bbSAlexander V. Chernikov /* We've got valid table in @tc. Let's add data */ 2249f7d47b0SAlexander V. Chernikov kidx = tc->no.kidx; 2259f7d47b0SAlexander V. Chernikov ta = tc->ta; 226adea6201SAlexander V. Chernikov num = 0; 2279f7d47b0SAlexander V. Chernikov 228b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 229adea6201SAlexander V. Chernikov error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, 230adea6201SAlexander V. Chernikov &aflags, &num); 2313b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2329f7d47b0SAlexander V. Chernikov 233ac35ff17SAlexander V. Chernikov /* Update number of records. */ 234adea6201SAlexander V. Chernikov if (error == 0) 235adea6201SAlexander V. Chernikov tc->count += num; 2369f7d47b0SAlexander V. Chernikov 237db785d31SAlexander V. Chernikov tc->flags = aflags; 238db785d31SAlexander V. Chernikov 239b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 240b074b7bbSAlexander V. Chernikov 241ac35ff17SAlexander V. Chernikov /* Run cleaning callback anyway */ 24268394ec8SAlexander V. Chernikov ta->flush_entry(ch, tei, &ta_buf); 243b074b7bbSAlexander V. Chernikov 2449f7d47b0SAlexander V. Chernikov return (error); 2453b3a8eb9SGleb Smirnoff } 2463b3a8eb9SGleb Smirnoff 2473b3a8eb9SGleb Smirnoff int 2481832a7b3SAlexander V. Chernikov del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 249b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 2503b3a8eb9SGleb Smirnoff { 251b074b7bbSAlexander V. Chernikov struct table_config *tc; 2529f7d47b0SAlexander V. Chernikov struct table_algo *ta; 253b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 254b074b7bbSAlexander V. Chernikov uint16_t kidx; 2559f7d47b0SAlexander V. Chernikov int error; 256adea6201SAlexander V. Chernikov uint32_t num; 257db785d31SAlexander V. Chernikov uint64_t aflags; 2589f7d47b0SAlexander V. Chernikov char ta_buf[128]; 2593b3a8eb9SGleb Smirnoff 2609f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 261b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 262b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 2639f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2643b3a8eb9SGleb Smirnoff return (ESRCH); 2653b3a8eb9SGleb Smirnoff } 2663b3a8eb9SGleb Smirnoff 267b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 2689f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2693b3a8eb9SGleb Smirnoff return (EINVAL); 2703b3a8eb9SGleb Smirnoff } 2719f7d47b0SAlexander V. Chernikov 272db785d31SAlexander V. Chernikov aflags = tc->flags; 2739f7d47b0SAlexander V. Chernikov ta = tc->ta; 2749f7d47b0SAlexander V. Chernikov 275db785d31SAlexander V. Chernikov if (aflags != 0) { 276db785d31SAlexander V. Chernikov 277db785d31SAlexander V. Chernikov /* 278db785d31SAlexander V. Chernikov * Give the chance to algo to shrink its state. 279db785d31SAlexander V. Chernikov */ 280db785d31SAlexander V. Chernikov tc->no.refcnt++; 281db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 282db785d31SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 283db785d31SAlexander V. Chernikov 284db785d31SAlexander V. Chernikov error = modify_table(ch, tc, ta, &ta_buf, aflags); 285db785d31SAlexander V. Chernikov 286db785d31SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 287db785d31SAlexander V. Chernikov tc->no.refcnt--; 288db785d31SAlexander V. Chernikov aflags = tc->flags; 289db785d31SAlexander V. Chernikov 290db785d31SAlexander V. Chernikov if (error != 0) { 291db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 292db785d31SAlexander V. Chernikov return (error); 293db785d31SAlexander V. Chernikov } 294db785d31SAlexander V. Chernikov } 295db785d31SAlexander V. Chernikov 296db785d31SAlexander V. Chernikov /* 297db785d31SAlexander V. Chernikov * We assume ta_buf size is enough for storing 298db785d31SAlexander V. Chernikov * prepare_del() key, so we're running under UH_LOCK here. 299db785d31SAlexander V. Chernikov */ 3009f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 30168394ec8SAlexander V. Chernikov if ((error = ta->prepare_del(ch, tei, &ta_buf)) != 0) { 3029f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3039f7d47b0SAlexander V. Chernikov return (error); 3049f7d47b0SAlexander V. Chernikov } 3059f7d47b0SAlexander V. Chernikov 306b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 307adea6201SAlexander V. Chernikov num = 0; 308b074b7bbSAlexander V. Chernikov 309b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 310adea6201SAlexander V. Chernikov error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, 311adea6201SAlexander V. Chernikov &aflags, &num); 3123b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 3133b3a8eb9SGleb Smirnoff 3149f7d47b0SAlexander V. Chernikov if (error == 0) 315adea6201SAlexander V. Chernikov tc->count -= num; 316db785d31SAlexander V. Chernikov tc->flags = aflags; 317b074b7bbSAlexander V. Chernikov 3189f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3193b3a8eb9SGleb Smirnoff 32068394ec8SAlexander V. Chernikov ta->flush_entry(ch, tei, &ta_buf); 321ac35ff17SAlexander V. Chernikov 322ac35ff17SAlexander V. Chernikov return (error); 323ac35ff17SAlexander V. Chernikov } 324ac35ff17SAlexander V. Chernikov 325db785d31SAlexander V. Chernikov /* 326db785d31SAlexander V. Chernikov * Runs callbacks to modify algo state (typically, table resize). 327db785d31SAlexander V. Chernikov * 328db785d31SAlexander V. Chernikov * Callbacks order: 329db785d31SAlexander V. Chernikov * 1) alloc_modify (no locks, M_WAITOK) - alloc new state based on @pflags. 330db785d31SAlexander V. Chernikov * 2) prepare_modifyt (UH_WLOCK) - copy old data into new storage 331db785d31SAlexander V. Chernikov * 3) modify (UH_WLOCK + WLOCK) - switch pointers 332db785d31SAlexander V. Chernikov * 4) flush_modify (no locks) - free state, if needed 333db785d31SAlexander V. Chernikov */ 334db785d31SAlexander V. Chernikov static int 335db785d31SAlexander V. Chernikov modify_table(struct ip_fw_chain *ch, struct table_config *tc, 336db785d31SAlexander V. Chernikov struct table_algo *ta, void *ta_buf, uint64_t pflags) 337db785d31SAlexander V. Chernikov { 338db785d31SAlexander V. Chernikov struct table_info *ti; 339db785d31SAlexander V. Chernikov int error; 340db785d31SAlexander V. Chernikov 341db785d31SAlexander V. Chernikov error = ta->prepare_mod(ta_buf, &pflags); 342db785d31SAlexander V. Chernikov if (error != 0) 343db785d31SAlexander V. Chernikov return (error); 344db785d31SAlexander V. Chernikov 345db785d31SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 346db785d31SAlexander V. Chernikov ti = KIDX_TO_TI(ch, tc->no.kidx); 347db785d31SAlexander V. Chernikov 34868394ec8SAlexander V. Chernikov error = ta->fill_mod(tc->astate, ti, ta_buf, &pflags); 349db785d31SAlexander V. Chernikov 350db785d31SAlexander V. Chernikov /* 351db785d31SAlexander V. Chernikov * prepare_mofify may return zero in @pflags to 352db785d31SAlexander V. Chernikov * indicate that modifications are not unnesessary. 353db785d31SAlexander V. Chernikov */ 354db785d31SAlexander V. Chernikov 355db785d31SAlexander V. Chernikov if (error == 0 && pflags != 0) { 356db785d31SAlexander V. Chernikov /* Do actual modification */ 357db785d31SAlexander V. Chernikov IPFW_WLOCK(ch); 35868394ec8SAlexander V. Chernikov ta->modify(tc->astate, ti, ta_buf, pflags); 359db785d31SAlexander V. Chernikov IPFW_WUNLOCK(ch); 360db785d31SAlexander V. Chernikov } 361db785d31SAlexander V. Chernikov 362db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 363db785d31SAlexander V. Chernikov 364db785d31SAlexander V. Chernikov ta->flush_mod(ta_buf); 365db785d31SAlexander V. Chernikov 366db785d31SAlexander V. Chernikov return (error); 367db785d31SAlexander V. Chernikov } 368db785d31SAlexander V. Chernikov 369ac35ff17SAlexander V. Chernikov int 370db785d31SAlexander V. Chernikov ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 371ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 372ac35ff17SAlexander V. Chernikov { 373ac35ff17SAlexander V. Chernikov int error; 374ac35ff17SAlexander V. Chernikov 375ac35ff17SAlexander V. Chernikov switch (op3->version) { 376ac35ff17SAlexander V. Chernikov case 0: 377db785d31SAlexander V. Chernikov error = ipfw_manage_table_ent_v0(ch, op3, sd); 378ac35ff17SAlexander V. Chernikov break; 379ac35ff17SAlexander V. Chernikov case 1: 380db785d31SAlexander V. Chernikov error = ipfw_manage_table_ent_v1(ch, op3, sd); 381ac35ff17SAlexander V. Chernikov break; 382ac35ff17SAlexander V. Chernikov default: 383ac35ff17SAlexander V. Chernikov error = ENOTSUP; 384ac35ff17SAlexander V. Chernikov } 385ac35ff17SAlexander V. Chernikov 386ac35ff17SAlexander V. Chernikov return (error); 387ac35ff17SAlexander V. Chernikov } 388ac35ff17SAlexander V. Chernikov 389ac35ff17SAlexander V. Chernikov /* 390ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 391ac35ff17SAlexander V. Chernikov * Data layout (v0): 392ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ipfw_table_xentry ] 393ac35ff17SAlexander V. Chernikov * 394ac35ff17SAlexander V. Chernikov * Returns 0 on success 395ac35ff17SAlexander V. Chernikov */ 396ac35ff17SAlexander V. Chernikov static int 397db785d31SAlexander V. Chernikov ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 398ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 399ac35ff17SAlexander V. Chernikov { 400ac35ff17SAlexander V. Chernikov ipfw_table_xentry *xent; 401ac35ff17SAlexander V. Chernikov struct tentry_info tei; 402ac35ff17SAlexander V. Chernikov struct tid_info ti; 403ac35ff17SAlexander V. Chernikov int error, hdrlen, read; 404ac35ff17SAlexander V. Chernikov 405ac35ff17SAlexander V. Chernikov hdrlen = offsetof(ipfw_table_xentry, k); 406ac35ff17SAlexander V. Chernikov 407ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 408ac35ff17SAlexander V. Chernikov if (sd->valsize < (sizeof(*op3) + hdrlen)) 409ac35ff17SAlexander V. Chernikov return (EINVAL); 410ac35ff17SAlexander V. Chernikov 411ac35ff17SAlexander V. Chernikov read = sizeof(ip_fw3_opheader); 412ac35ff17SAlexander V. Chernikov 413ac35ff17SAlexander V. Chernikov /* Check if xentry len field is valid */ 414ac35ff17SAlexander V. Chernikov xent = (ipfw_table_xentry *)(op3 + 1); 415ac35ff17SAlexander V. Chernikov if (xent->len < hdrlen || xent->len + read > sd->valsize) 416ac35ff17SAlexander V. Chernikov return (EINVAL); 417ac35ff17SAlexander V. Chernikov 418ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 419ac35ff17SAlexander V. Chernikov tei.paddr = &xent->k; 420ac35ff17SAlexander V. Chernikov tei.masklen = xent->masklen; 421ac35ff17SAlexander V. Chernikov tei.value = xent->value; 422ac35ff17SAlexander V. Chernikov /* Old requests compability */ 423db785d31SAlexander V. Chernikov tei.flags = TEI_FLAGS_COMPAT; 424ac35ff17SAlexander V. Chernikov if (xent->type == IPFW_TABLE_CIDR) { 425ac35ff17SAlexander V. Chernikov if (xent->len - hdrlen == sizeof(in_addr_t)) 426ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET; 427ac35ff17SAlexander V. Chernikov else 428ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET6; 429ac35ff17SAlexander V. Chernikov } 430ac35ff17SAlexander V. Chernikov 431ac35ff17SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 432ac35ff17SAlexander V. Chernikov ti.uidx = xent->tbl; 433ac35ff17SAlexander V. Chernikov ti.type = xent->type; 434ac35ff17SAlexander V. Chernikov 435ac35ff17SAlexander V. Chernikov error = (op3->opcode == IP_FW_TABLE_XADD) ? 4361832a7b3SAlexander V. Chernikov add_table_entry(ch, &ti, &tei) : 4371832a7b3SAlexander V. Chernikov del_table_entry(ch, &ti, &tei); 438ac35ff17SAlexander V. Chernikov 439ac35ff17SAlexander V. Chernikov return (error); 440ac35ff17SAlexander V. Chernikov } 441ac35ff17SAlexander V. Chernikov 442ac35ff17SAlexander V. Chernikov /* 443ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 444ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 445db785d31SAlexander V. Chernikov * Request: [ ipfw_obj_header 446db785d31SAlexander V. Chernikov * ipfw_obj_ctlv(IPFW_TLV_TBLENT_LIST) [ ipfw_obj_tentry x N ] 447db785d31SAlexander V. Chernikov * ] 448ac35ff17SAlexander V. Chernikov * 449ac35ff17SAlexander V. Chernikov * Returns 0 on success 450ac35ff17SAlexander V. Chernikov */ 451ac35ff17SAlexander V. Chernikov static int 452db785d31SAlexander V. Chernikov ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 453ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 454ac35ff17SAlexander V. Chernikov { 455ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent; 456db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 457ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 458ac35ff17SAlexander V. Chernikov struct tentry_info tei; 459ac35ff17SAlexander V. Chernikov struct tid_info ti; 460ac35ff17SAlexander V. Chernikov int error, read; 461ac35ff17SAlexander V. Chernikov 462ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 463db785d31SAlexander V. Chernikov if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv))) 464ac35ff17SAlexander V. Chernikov return (EINVAL); 465ac35ff17SAlexander V. Chernikov 466ac35ff17SAlexander V. Chernikov /* Check if passed data is too long */ 467ac35ff17SAlexander V. Chernikov if (sd->valsize != sd->kavail) 468ac35ff17SAlexander V. Chernikov return (EINVAL); 469ac35ff17SAlexander V. Chernikov 470ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)sd->kbuf; 471ac35ff17SAlexander V. Chernikov 472ac35ff17SAlexander V. Chernikov /* Basic length checks for TLVs */ 473ac35ff17SAlexander V. Chernikov if (oh->ntlv.head.length != sizeof(oh->ntlv)) 474ac35ff17SAlexander V. Chernikov return (EINVAL); 475ac35ff17SAlexander V. Chernikov 476ac35ff17SAlexander V. Chernikov read = sizeof(*oh); 477ac35ff17SAlexander V. Chernikov 478db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 479db785d31SAlexander V. Chernikov if (ctlv->head.length + read != sd->valsize) 480db785d31SAlexander V. Chernikov return (EINVAL); 481db785d31SAlexander V. Chernikov 482db785d31SAlexander V. Chernikov /* 483db785d31SAlexander V. Chernikov * TODO: permit adding multiple entries for given table 484db785d31SAlexander V. Chernikov * at once 485db785d31SAlexander V. Chernikov */ 486db785d31SAlexander V. Chernikov if (ctlv->count != 1) 487db785d31SAlexander V. Chernikov return (EOPNOTSUPP); 488db785d31SAlexander V. Chernikov 489db785d31SAlexander V. Chernikov read += sizeof(*ctlv); 490db785d31SAlexander V. Chernikov 491ac35ff17SAlexander V. Chernikov /* Assume tentry may grow to support larger keys */ 492db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 493ac35ff17SAlexander V. Chernikov if (tent->head.length < sizeof(*tent) || 494ac35ff17SAlexander V. Chernikov tent->head.length + read > sd->valsize) 495ac35ff17SAlexander V. Chernikov return (EINVAL); 496ac35ff17SAlexander V. Chernikov 49781d3153dSAlexander V. Chernikov /* Convert data into kernel request objects */ 498ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 499ac35ff17SAlexander V. Chernikov tei.paddr = &tent->k; 500ac35ff17SAlexander V. Chernikov tei.subtype = tent->subtype; 501ac35ff17SAlexander V. Chernikov tei.masklen = tent->masklen; 50281d3153dSAlexander V. Chernikov if (tent->head.flags & IPFW_TF_UPDATE) 503ac35ff17SAlexander V. Chernikov tei.flags |= TEI_FLAGS_UPDATE; 504ac35ff17SAlexander V. Chernikov tei.value = tent->value; 505ac35ff17SAlexander V. Chernikov 50681d3153dSAlexander V. Chernikov objheader_to_ti(oh, &ti); 507ac35ff17SAlexander V. Chernikov ti.type = oh->ntlv.type; 50881d3153dSAlexander V. Chernikov ti.uidx = tent->idx; 509ac35ff17SAlexander V. Chernikov 510ac35ff17SAlexander V. Chernikov error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ? 5111832a7b3SAlexander V. Chernikov add_table_entry(ch, &ti, &tei) : 5121832a7b3SAlexander V. Chernikov del_table_entry(ch, &ti, &tei); 513ac35ff17SAlexander V. Chernikov 514ac35ff17SAlexander V. Chernikov return (error); 515ac35ff17SAlexander V. Chernikov } 516ac35ff17SAlexander V. Chernikov 51781d3153dSAlexander V. Chernikov /* 51881d3153dSAlexander V. Chernikov * Looks up an entry in given table. 51981d3153dSAlexander V. Chernikov * Data layout (v0)(current): 52081d3153dSAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_obj_tentry ] 52181d3153dSAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_obj_tentry ] 52281d3153dSAlexander V. Chernikov * 52381d3153dSAlexander V. Chernikov * Returns 0 on success 52481d3153dSAlexander V. Chernikov */ 52581d3153dSAlexander V. Chernikov int 52681d3153dSAlexander V. Chernikov ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 52781d3153dSAlexander V. Chernikov struct sockopt_data *sd) 52881d3153dSAlexander V. Chernikov { 52981d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 53081d3153dSAlexander V. Chernikov ipfw_obj_header *oh; 53181d3153dSAlexander V. Chernikov struct tid_info ti; 53281d3153dSAlexander V. Chernikov struct table_config *tc; 53381d3153dSAlexander V. Chernikov struct table_algo *ta; 53481d3153dSAlexander V. Chernikov struct table_info *kti; 53581d3153dSAlexander V. Chernikov struct namedobj_instance *ni; 53681d3153dSAlexander V. Chernikov int error, plen; 53781d3153dSAlexander V. Chernikov void *paddr; 53881d3153dSAlexander V. Chernikov size_t sz; 53981d3153dSAlexander V. Chernikov 54081d3153dSAlexander V. Chernikov /* Check minimum header size */ 54181d3153dSAlexander V. Chernikov sz = sizeof(*oh) + sizeof(*tent); 54281d3153dSAlexander V. Chernikov if (sd->valsize != sz) 54381d3153dSAlexander V. Chernikov return (EINVAL); 54481d3153dSAlexander V. Chernikov 54581d3153dSAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 54681d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 54781d3153dSAlexander V. Chernikov 54881d3153dSAlexander V. Chernikov /* Basic length checks for TLVs */ 54981d3153dSAlexander V. Chernikov if (oh->ntlv.head.length != sizeof(oh->ntlv)) 55081d3153dSAlexander V. Chernikov return (EINVAL); 55181d3153dSAlexander V. Chernikov 55281d3153dSAlexander V. Chernikov objheader_to_ti(oh, &ti); 55381d3153dSAlexander V. Chernikov ti.type = oh->ntlv.type; 55481d3153dSAlexander V. Chernikov ti.uidx = tent->idx; 55581d3153dSAlexander V. Chernikov 55681d3153dSAlexander V. Chernikov IPFW_UH_RLOCK(ch); 55781d3153dSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 55881d3153dSAlexander V. Chernikov 55981d3153dSAlexander V. Chernikov /* 56081d3153dSAlexander V. Chernikov * Find existing table and check its type . 56181d3153dSAlexander V. Chernikov */ 56281d3153dSAlexander V. Chernikov ta = NULL; 56381d3153dSAlexander V. Chernikov if ((tc = find_table(ni, &ti)) == NULL) { 56481d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 56581d3153dSAlexander V. Chernikov return (ESRCH); 56681d3153dSAlexander V. Chernikov } 56781d3153dSAlexander V. Chernikov 56881d3153dSAlexander V. Chernikov /* check table type */ 56981d3153dSAlexander V. Chernikov if (tc->no.type != ti.type) { 57081d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 57181d3153dSAlexander V. Chernikov return (EINVAL); 57281d3153dSAlexander V. Chernikov } 57381d3153dSAlexander V. Chernikov 57481d3153dSAlexander V. Chernikov /* Check lookup key for validness */ 57581d3153dSAlexander V. Chernikov plen = 0; 57681d3153dSAlexander V. Chernikov paddr = &tent->k; 57781d3153dSAlexander V. Chernikov switch (ti.type) 57881d3153dSAlexander V. Chernikov { 57981d3153dSAlexander V. Chernikov case IPFW_TABLE_CIDR: 58081d3153dSAlexander V. Chernikov if (tent->subtype == AF_INET) 58181d3153dSAlexander V. Chernikov plen = sizeof(struct in_addr); 58281d3153dSAlexander V. Chernikov else if (tent->subtype == AF_INET6) 58381d3153dSAlexander V. Chernikov plen = sizeof(struct in6_addr); 58481d3153dSAlexander V. Chernikov else { 58581d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 58681d3153dSAlexander V. Chernikov return (EINVAL); 58781d3153dSAlexander V. Chernikov } 58881d3153dSAlexander V. Chernikov break; 58981d3153dSAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 59081d3153dSAlexander V. Chernikov /* Check key first */ 59181d3153dSAlexander V. Chernikov plen = sizeof(tent->k.iface); 59281d3153dSAlexander V. Chernikov if (strnlen(tent->k.iface, plen) == plen) { 59381d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 59481d3153dSAlexander V. Chernikov return (EINVAL); 59581d3153dSAlexander V. Chernikov } 596b23d5de9SAlexander V. Chernikov case IPFW_TABLE_NUMBER: 597b23d5de9SAlexander V. Chernikov plen = sizeof(uint32_t); 598b23d5de9SAlexander V. Chernikov break; 59981d3153dSAlexander V. Chernikov 60081d3153dSAlexander V. Chernikov break; 60181d3153dSAlexander V. Chernikov default: 60281d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 60381d3153dSAlexander V. Chernikov return (ENOTSUP); 60481d3153dSAlexander V. Chernikov } 60581d3153dSAlexander V. Chernikov kti = KIDX_TO_TI(ch, tc->no.kidx); 60681d3153dSAlexander V. Chernikov ta = tc->ta; 60781d3153dSAlexander V. Chernikov 60881d3153dSAlexander V. Chernikov error = ta->find_tentry(tc->astate, kti, paddr, plen, tent); 60981d3153dSAlexander V. Chernikov 61081d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 61181d3153dSAlexander V. Chernikov 61281d3153dSAlexander V. Chernikov return (error); 61381d3153dSAlexander V. Chernikov } 61481d3153dSAlexander V. Chernikov 615ac35ff17SAlexander V. Chernikov int 616ac35ff17SAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 617ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 618ac35ff17SAlexander V. Chernikov { 619ac35ff17SAlexander V. Chernikov int error; 620ac35ff17SAlexander V. Chernikov struct _ipfw_obj_header *oh; 621ac35ff17SAlexander V. Chernikov struct tid_info ti; 622ac35ff17SAlexander V. Chernikov 623ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh)) 624ac35ff17SAlexander V. Chernikov return (EINVAL); 625ac35ff17SAlexander V. Chernikov 626ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)op3; 627ac35ff17SAlexander V. Chernikov objheader_to_ti(oh, &ti); 628ac35ff17SAlexander V. Chernikov 6291832a7b3SAlexander V. Chernikov if (op3->opcode == IP_FW_TABLE_XDESTROY) 630ac35ff17SAlexander V. Chernikov error = destroy_table(ch, &ti); 6311832a7b3SAlexander V. Chernikov else if (op3->opcode == IP_FW_TABLE_XFLUSH) 632ac35ff17SAlexander V. Chernikov error = flush_table(ch, &ti); 633ac35ff17SAlexander V. Chernikov else 634ac35ff17SAlexander V. Chernikov return (ENOTSUP); 635ac35ff17SAlexander V. Chernikov 636ac35ff17SAlexander V. Chernikov return (error); 6373b3a8eb9SGleb Smirnoff } 6383b3a8eb9SGleb Smirnoff 639b074b7bbSAlexander V. Chernikov /* 6409f7d47b0SAlexander V. Chernikov * Flushes all entries in given table. 641ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 642ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 643ac35ff17SAlexander V. Chernikov * 644ac35ff17SAlexander V. Chernikov * Returns 0 on success 645b074b7bbSAlexander V. Chernikov */ 6461832a7b3SAlexander V. Chernikov int 647ac35ff17SAlexander V. Chernikov flush_table(struct ip_fw_chain *ch, struct tid_info *ti) 6483b3a8eb9SGleb Smirnoff { 649b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 650b074b7bbSAlexander V. Chernikov struct table_config *tc; 6519f7d47b0SAlexander V. Chernikov struct table_algo *ta; 6529f7d47b0SAlexander V. Chernikov struct table_info ti_old, ti_new, *tablestate; 6539f7d47b0SAlexander V. Chernikov void *astate_old, *astate_new; 654daabb523SAlexander V. Chernikov char algostate[32], *pstate; 655b074b7bbSAlexander V. Chernikov int error; 656b074b7bbSAlexander V. Chernikov uint16_t kidx; 6573b3a8eb9SGleb Smirnoff 6583b3a8eb9SGleb Smirnoff /* 6599f7d47b0SAlexander V. Chernikov * Stage 1: save table algoritm. 660b074b7bbSAlexander V. Chernikov * Reference found table to ensure it won't disappear. 6613b3a8eb9SGleb Smirnoff */ 662b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 663b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 664b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 665b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 666b074b7bbSAlexander V. Chernikov return (ESRCH); 667b074b7bbSAlexander V. Chernikov } 6689f7d47b0SAlexander V. Chernikov ta = tc->ta; 669b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 670daabb523SAlexander V. Chernikov /* Save statup algo parameters */ 671daabb523SAlexander V. Chernikov if (ta->print_config != NULL) { 672daabb523SAlexander V. Chernikov ta->print_config(tc->astate, KIDX_TO_TI(ch, tc->no.kidx), 673daabb523SAlexander V. Chernikov algostate, sizeof(algostate)); 674daabb523SAlexander V. Chernikov pstate = algostate; 675daabb523SAlexander V. Chernikov } else 676daabb523SAlexander V. Chernikov pstate = NULL; 677b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 6783b3a8eb9SGleb Smirnoff 679b074b7bbSAlexander V. Chernikov /* 6809f7d47b0SAlexander V. Chernikov * Stage 2: allocate new table instance using same algo. 681b074b7bbSAlexander V. Chernikov */ 6829f7d47b0SAlexander V. Chernikov memset(&ti_new, 0, sizeof(struct table_info)); 683daabb523SAlexander V. Chernikov if ((error = ta->init(ch, &astate_new, &ti_new, pstate)) != 0) { 684b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 685b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 686b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 687b074b7bbSAlexander V. Chernikov return (error); 688b074b7bbSAlexander V. Chernikov } 689b074b7bbSAlexander V. Chernikov 690b074b7bbSAlexander V. Chernikov /* 691b074b7bbSAlexander V. Chernikov * Stage 3: swap old state pointers with newly-allocated ones. 692b074b7bbSAlexander V. Chernikov * Decrease refcount. 693b074b7bbSAlexander V. Chernikov */ 694b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 695b074b7bbSAlexander V. Chernikov 696b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 697b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 6989f7d47b0SAlexander V. Chernikov tablestate = (struct table_info *)ch->tablestate; 699b074b7bbSAlexander V. Chernikov 7009f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 7019f7d47b0SAlexander V. Chernikov ti_old = tablestate[kidx]; 7029f7d47b0SAlexander V. Chernikov tablestate[kidx] = ti_new; 7039f7d47b0SAlexander V. Chernikov IPFW_WUNLOCK(ch); 704b074b7bbSAlexander V. Chernikov 7059f7d47b0SAlexander V. Chernikov astate_old = tc->astate; 7069f7d47b0SAlexander V. Chernikov tc->astate = astate_new; 7079f7d47b0SAlexander V. Chernikov tc->ti = ti_new; 7089f7d47b0SAlexander V. Chernikov tc->count = 0; 709b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 710b074b7bbSAlexander V. Chernikov 711b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 7123b3a8eb9SGleb Smirnoff 713b074b7bbSAlexander V. Chernikov /* 714b074b7bbSAlexander V. Chernikov * Stage 4: perform real flush. 715b074b7bbSAlexander V. Chernikov */ 7169f7d47b0SAlexander V. Chernikov ta->destroy(astate_old, &ti_old); 7173b3a8eb9SGleb Smirnoff 7183b3a8eb9SGleb Smirnoff return (0); 7193b3a8eb9SGleb Smirnoff } 7203b3a8eb9SGleb Smirnoff 721b074b7bbSAlexander V. Chernikov /* 7229f7d47b0SAlexander V. Chernikov * Destroys table specified by @ti. 723ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 724ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 725ac35ff17SAlexander V. Chernikov * 726ac35ff17SAlexander V. Chernikov * Returns 0 on success 727b074b7bbSAlexander V. Chernikov */ 728ac35ff17SAlexander V. Chernikov static int 729ac35ff17SAlexander V. Chernikov destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) 730b074b7bbSAlexander V. Chernikov { 731b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 732b074b7bbSAlexander V. Chernikov struct table_config *tc; 733b074b7bbSAlexander V. Chernikov 734b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 735b074b7bbSAlexander V. Chernikov 736b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 737b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 738b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 739b074b7bbSAlexander V. Chernikov return (ESRCH); 740b074b7bbSAlexander V. Chernikov } 741b074b7bbSAlexander V. Chernikov 7429f7d47b0SAlexander V. Chernikov /* Do not permit destroying referenced tables */ 7439f7d47b0SAlexander V. Chernikov if (tc->no.refcnt > 0) { 744b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 745b074b7bbSAlexander V. Chernikov return (EBUSY); 746b074b7bbSAlexander V. Chernikov } 747b074b7bbSAlexander V. Chernikov 748b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 749b074b7bbSAlexander V. Chernikov unlink_table(ch, tc); 750b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 751b074b7bbSAlexander V. Chernikov 752b074b7bbSAlexander V. Chernikov /* Free obj index */ 753ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0) 754b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 755b074b7bbSAlexander V. Chernikov tc->no.kidx, tc->tablename); 756b074b7bbSAlexander V. Chernikov 757b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 758b074b7bbSAlexander V. Chernikov 759b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 760b074b7bbSAlexander V. Chernikov 761b074b7bbSAlexander V. Chernikov return (0); 762b074b7bbSAlexander V. Chernikov } 763b074b7bbSAlexander V. Chernikov 764b074b7bbSAlexander V. Chernikov static void 765b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, 766b074b7bbSAlexander V. Chernikov void *arg) 767b074b7bbSAlexander V. Chernikov { 768b074b7bbSAlexander V. Chernikov 769b074b7bbSAlexander V. Chernikov unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); 770ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, no->kidx) != 0) 771b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 772b074b7bbSAlexander V. Chernikov no->kidx, no->name); 773b074b7bbSAlexander V. Chernikov free_table_config(ni, (struct table_config *)no); 774b074b7bbSAlexander V. Chernikov } 775b074b7bbSAlexander V. Chernikov 7763b3a8eb9SGleb Smirnoff void 7773b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch) 7783b3a8eb9SGleb Smirnoff { 7793b3a8eb9SGleb Smirnoff 780b074b7bbSAlexander V. Chernikov /* Remove all tables from working set */ 781b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 782b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 783b074b7bbSAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); 784b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 785b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 7863b3a8eb9SGleb Smirnoff 7873b3a8eb9SGleb Smirnoff /* Free pointers itself */ 7889f7d47b0SAlexander V. Chernikov free(ch->tablestate, M_IPFW); 7899f7d47b0SAlexander V. Chernikov 7909f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(ch); 791b074b7bbSAlexander V. Chernikov 792b074b7bbSAlexander V. Chernikov ipfw_objhash_destroy(CHAIN_TO_NI(ch)); 793b074b7bbSAlexander V. Chernikov free(CHAIN_TO_TCFG(ch), M_IPFW); 7943b3a8eb9SGleb Smirnoff } 7953b3a8eb9SGleb Smirnoff 7963b3a8eb9SGleb Smirnoff int 7973b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch) 7983b3a8eb9SGleb Smirnoff { 799b074b7bbSAlexander V. Chernikov struct tables_config *tcfg; 800b074b7bbSAlexander V. Chernikov 8013b3a8eb9SGleb Smirnoff /* Allocate pointers */ 8029f7d47b0SAlexander V. Chernikov ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), 8039f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 804b074b7bbSAlexander V. Chernikov 805b074b7bbSAlexander V. Chernikov tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); 806b074b7bbSAlexander V. Chernikov tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); 807b074b7bbSAlexander V. Chernikov ch->tblcfg = tcfg; 808b074b7bbSAlexander V. Chernikov 8099f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(ch); 8109f7d47b0SAlexander V. Chernikov 8113b3a8eb9SGleb Smirnoff return (0); 8123b3a8eb9SGleb Smirnoff } 8133b3a8eb9SGleb Smirnoff 8143b3a8eb9SGleb Smirnoff int 8153b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) 8163b3a8eb9SGleb Smirnoff { 8173b3a8eb9SGleb Smirnoff unsigned int ntables_old, tbl; 818b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 8199f7d47b0SAlexander V. Chernikov void *new_idx, *old_tablestate, *tablestate; 82068394ec8SAlexander V. Chernikov struct table_info *ti; 82168394ec8SAlexander V. Chernikov struct table_config *tc; 82268394ec8SAlexander V. Chernikov int i, new_blocks; 8233b3a8eb9SGleb Smirnoff 8243b3a8eb9SGleb Smirnoff /* Check new value for validity */ 8253b3a8eb9SGleb Smirnoff if (ntables > IPFW_TABLES_MAX) 8263b3a8eb9SGleb Smirnoff ntables = IPFW_TABLES_MAX; 8273b3a8eb9SGleb Smirnoff 8283b3a8eb9SGleb Smirnoff /* Allocate new pointers */ 8299f7d47b0SAlexander V. Chernikov tablestate = malloc(ntables * sizeof(struct table_info), 8309f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 8319f7d47b0SAlexander V. Chernikov 832b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); 8333b3a8eb9SGleb Smirnoff 8349f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 8353b3a8eb9SGleb Smirnoff 8363b3a8eb9SGleb Smirnoff tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables; 837b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 838b074b7bbSAlexander V. Chernikov 8399f7d47b0SAlexander V. Chernikov /* Temporary restrict decreasing max_tables */ 8409f7d47b0SAlexander V. Chernikov if (ntables < V_fw_tables_max) { 8419f7d47b0SAlexander V. Chernikov 8429f7d47b0SAlexander V. Chernikov /* 8439f7d47b0SAlexander V. Chernikov * FIXME: Check if we really can shrink 8449f7d47b0SAlexander V. Chernikov */ 8459f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 846b074b7bbSAlexander V. Chernikov return (EINVAL); 847b074b7bbSAlexander V. Chernikov } 8483b3a8eb9SGleb Smirnoff 8499f7d47b0SAlexander V. Chernikov /* Copy table info/indices */ 8509f7d47b0SAlexander V. Chernikov memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl); 8519f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks); 8523b3a8eb9SGleb Smirnoff 8539f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 8549f7d47b0SAlexander V. Chernikov 8559f7d47b0SAlexander V. Chernikov /* Change pointers */ 8569f7d47b0SAlexander V. Chernikov old_tablestate = ch->tablestate; 8579f7d47b0SAlexander V. Chernikov ch->tablestate = tablestate; 8589f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks); 8593b3a8eb9SGleb Smirnoff 8603b3a8eb9SGleb Smirnoff ntables_old = V_fw_tables_max; 8613b3a8eb9SGleb Smirnoff V_fw_tables_max = ntables; 8623b3a8eb9SGleb Smirnoff 8633b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 86468394ec8SAlexander V. Chernikov 86568394ec8SAlexander V. Chernikov /* Notify all consumers that their @ti pointer has changed */ 86668394ec8SAlexander V. Chernikov ti = (struct table_info *)ch->tablestate; 86768394ec8SAlexander V. Chernikov for (i = 0; i < tbl; i++, ti++) { 86868394ec8SAlexander V. Chernikov if (ti->lookup == NULL) 86968394ec8SAlexander V. Chernikov continue; 87068394ec8SAlexander V. Chernikov tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, i); 87168394ec8SAlexander V. Chernikov if (tc == NULL || tc->ta->change_ti == NULL) 87268394ec8SAlexander V. Chernikov continue; 87368394ec8SAlexander V. Chernikov 87468394ec8SAlexander V. Chernikov tc->ta->change_ti(tc->astate, ti); 87568394ec8SAlexander V. Chernikov } 87668394ec8SAlexander V. Chernikov 8779f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 8783b3a8eb9SGleb Smirnoff 8793b3a8eb9SGleb Smirnoff /* Free old pointers */ 8809f7d47b0SAlexander V. Chernikov free(old_tablestate, M_IPFW); 881b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 8823b3a8eb9SGleb Smirnoff 8833b3a8eb9SGleb Smirnoff return (0); 8843b3a8eb9SGleb Smirnoff } 8853b3a8eb9SGleb Smirnoff 8863b3a8eb9SGleb Smirnoff int 8873b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 8883b3a8eb9SGleb Smirnoff uint32_t *val) 8893b3a8eb9SGleb Smirnoff { 8909f7d47b0SAlexander V. Chernikov struct table_info *ti; 8913b3a8eb9SGleb Smirnoff 8929f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 8939f7d47b0SAlexander V. Chernikov 8949f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, &addr, sizeof(in_addr_t), val)); 8953b3a8eb9SGleb Smirnoff } 8969f7d47b0SAlexander V. Chernikov 8979f7d47b0SAlexander V. Chernikov int 8989f7d47b0SAlexander V. Chernikov ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, 8999f7d47b0SAlexander V. Chernikov void *paddr, uint32_t *val) 9009f7d47b0SAlexander V. Chernikov { 9019f7d47b0SAlexander V. Chernikov struct table_info *ti; 9029f7d47b0SAlexander V. Chernikov 9039f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 9049f7d47b0SAlexander V. Chernikov 9059f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, paddr, plen, val)); 9069f7d47b0SAlexander V. Chernikov } 9079f7d47b0SAlexander V. Chernikov 9089f7d47b0SAlexander V. Chernikov /* 9099f7d47b0SAlexander V. Chernikov * Info/List/dump support for tables. 9109f7d47b0SAlexander V. Chernikov * 9119f7d47b0SAlexander V. Chernikov */ 9129f7d47b0SAlexander V. Chernikov 913f1220db8SAlexander V. Chernikov /* 914d3a4f924SAlexander V. Chernikov * High-level 'get' cmds sysctl handlers 915d3a4f924SAlexander V. Chernikov */ 916d3a4f924SAlexander V. Chernikov 917d3a4f924SAlexander V. Chernikov /* 918d3a4f924SAlexander V. Chernikov * Get buffer size needed to list info for all tables. 919ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 920d3a4f924SAlexander V. Chernikov * Request: [ empty ], size = sizeof(ipfw_obj_lheader) 921d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ] 922d3a4f924SAlexander V. Chernikov * 923d3a4f924SAlexander V. Chernikov * Returns 0 on success 924f1220db8SAlexander V. Chernikov */ 925f1220db8SAlexander V. Chernikov int 9262d99a349SAlexander V. Chernikov ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 927f1220db8SAlexander V. Chernikov { 928f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 929f1220db8SAlexander V. Chernikov 9302d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 9312d99a349SAlexander V. Chernikov if (olh == NULL) 932d3a4f924SAlexander V. Chernikov return (EINVAL); 933d3a4f924SAlexander V. Chernikov 934f1220db8SAlexander V. Chernikov olh->size = sizeof(*olh); /* Make export_table store needed size */ 935f1220db8SAlexander V. Chernikov 936f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 9372d99a349SAlexander V. Chernikov export_tables(ch, olh, sd); 938f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 939f1220db8SAlexander V. Chernikov 9402d99a349SAlexander V. Chernikov return (0); 941f1220db8SAlexander V. Chernikov } 942f1220db8SAlexander V. Chernikov 943d3a4f924SAlexander V. Chernikov /* 944d3a4f924SAlexander V. Chernikov * Lists all tables currently available in kernel. 945ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 946d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 947d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ] 948d3a4f924SAlexander V. Chernikov * 949d3a4f924SAlexander V. Chernikov * Returns 0 on success 950d3a4f924SAlexander V. Chernikov */ 951f1220db8SAlexander V. Chernikov int 9522d99a349SAlexander V. Chernikov ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 953f1220db8SAlexander V. Chernikov { 954f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 955f1220db8SAlexander V. Chernikov int error; 956f1220db8SAlexander V. Chernikov 9572d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 9582d99a349SAlexander V. Chernikov if (olh == NULL) 959d3a4f924SAlexander V. Chernikov return (EINVAL); 96068394ec8SAlexander V. Chernikov if (sd->valsize < olh->size) 96168394ec8SAlexander V. Chernikov return (EINVAL); 962d3a4f924SAlexander V. Chernikov 963f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 9642d99a349SAlexander V. Chernikov error = export_tables(ch, olh, sd); 965f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 966f1220db8SAlexander V. Chernikov 967f1220db8SAlexander V. Chernikov return (error); 968f1220db8SAlexander V. Chernikov } 969f1220db8SAlexander V. Chernikov 970f1220db8SAlexander V. Chernikov /* 9712d99a349SAlexander V. Chernikov * Store table info to buffer provided by @sd. 972ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 973d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info(empty)] 974d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ] 975d3a4f924SAlexander V. Chernikov * 976d3a4f924SAlexander V. Chernikov * Returns 0 on success. 977d3a4f924SAlexander V. Chernikov */ 978d3a4f924SAlexander V. Chernikov int 9792d99a349SAlexander V. Chernikov ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd) 980d3a4f924SAlexander V. Chernikov { 981d3a4f924SAlexander V. Chernikov struct _ipfw_obj_header *oh; 982d3a4f924SAlexander V. Chernikov struct table_config *tc; 983d3a4f924SAlexander V. Chernikov struct tid_info ti; 984d3a4f924SAlexander V. Chernikov size_t sz; 985d3a4f924SAlexander V. Chernikov 986d3a4f924SAlexander V. Chernikov sz = sizeof(*oh) + sizeof(ipfw_xtable_info); 9872d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 9882d99a349SAlexander V. Chernikov if (oh == NULL) 989d3a4f924SAlexander V. Chernikov return (EINVAL); 990d3a4f924SAlexander V. Chernikov 991d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 992d3a4f924SAlexander V. Chernikov 993d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 994d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 995d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 996d3a4f924SAlexander V. Chernikov return (ESRCH); 997d3a4f924SAlexander V. Chernikov } 998d3a4f924SAlexander V. Chernikov 999ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, (ipfw_xtable_info *)(oh + 1)); 1000d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1001d3a4f924SAlexander V. Chernikov 10022d99a349SAlexander V. Chernikov return (0); 1003d3a4f924SAlexander V. Chernikov } 1004d3a4f924SAlexander V. Chernikov 1005f1220db8SAlexander V. Chernikov struct dump_args { 1006f1220db8SAlexander V. Chernikov struct table_info *ti; 1007f1220db8SAlexander V. Chernikov struct table_config *tc; 10082d99a349SAlexander V. Chernikov struct sockopt_data *sd; 1009f1220db8SAlexander V. Chernikov uint32_t cnt; 1010f1220db8SAlexander V. Chernikov uint16_t uidx; 101181d3153dSAlexander V. Chernikov int error; 10122d99a349SAlexander V. Chernikov ipfw_table_entry *ent; 10132d99a349SAlexander V. Chernikov uint32_t size; 101481d3153dSAlexander V. Chernikov ipfw_obj_tentry tent; 1015f1220db8SAlexander V. Chernikov }; 1016f1220db8SAlexander V. Chernikov 1017f1220db8SAlexander V. Chernikov int 10182d99a349SAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 10192d99a349SAlexander V. Chernikov struct sockopt_data *sd) 1020f1220db8SAlexander V. Chernikov { 1021d3a4f924SAlexander V. Chernikov int error; 1022d3a4f924SAlexander V. Chernikov 1023d3a4f924SAlexander V. Chernikov switch (op3->version) { 1024d3a4f924SAlexander V. Chernikov case 0: 10252d99a349SAlexander V. Chernikov error = ipfw_dump_table_v0(ch, sd); 1026d3a4f924SAlexander V. Chernikov break; 1027d3a4f924SAlexander V. Chernikov case 1: 10282d99a349SAlexander V. Chernikov error = ipfw_dump_table_v1(ch, sd); 1029d3a4f924SAlexander V. Chernikov break; 1030d3a4f924SAlexander V. Chernikov default: 1031d3a4f924SAlexander V. Chernikov error = ENOTSUP; 1032d3a4f924SAlexander V. Chernikov } 1033d3a4f924SAlexander V. Chernikov 1034d3a4f924SAlexander V. Chernikov return (error); 1035d3a4f924SAlexander V. Chernikov } 1036d3a4f924SAlexander V. Chernikov 1037d3a4f924SAlexander V. Chernikov /* 1038d3a4f924SAlexander V. Chernikov * Dumps all table data 1039ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 10402d99a349SAlexander V. Chernikov * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size 104181d3153dSAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ] 1042d3a4f924SAlexander V. Chernikov * 1043d3a4f924SAlexander V. Chernikov * Returns 0 on success 1044d3a4f924SAlexander V. Chernikov */ 1045d3a4f924SAlexander V. Chernikov static int 10462d99a349SAlexander V. Chernikov ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd) 1047d3a4f924SAlexander V. Chernikov { 1048f1220db8SAlexander V. Chernikov struct _ipfw_obj_header *oh; 1049f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1050f1220db8SAlexander V. Chernikov struct tid_info ti; 1051f1220db8SAlexander V. Chernikov struct table_config *tc; 1052f1220db8SAlexander V. Chernikov struct table_algo *ta; 1053f1220db8SAlexander V. Chernikov struct dump_args da; 1054d3a4f924SAlexander V. Chernikov uint32_t sz; 1055f1220db8SAlexander V. Chernikov 10562d99a349SAlexander V. Chernikov sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 10572d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 10582d99a349SAlexander V. Chernikov if (oh == NULL) 1059d3a4f924SAlexander V. Chernikov return (EINVAL); 1060d3a4f924SAlexander V. Chernikov 10612d99a349SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 1062d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 1063f1220db8SAlexander V. Chernikov 1064f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 1065f1220db8SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 1066f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1067f1220db8SAlexander V. Chernikov return (ESRCH); 1068f1220db8SAlexander V. Chernikov } 1069ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, i); 10702d99a349SAlexander V. Chernikov sz = tc->count; 10712d99a349SAlexander V. Chernikov 107281d3153dSAlexander V. Chernikov if (sd->valsize < sz + tc->count * sizeof(ipfw_obj_tentry)) { 10732d99a349SAlexander V. Chernikov 10742d99a349SAlexander V. Chernikov /* 10752d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 10762d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 10772d99a349SAlexander V. Chernikov * relevant table info including size, so we 10782d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 10792d99a349SAlexander V. Chernikov */ 1080f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 10812d99a349SAlexander V. Chernikov return (ENOMEM); 1082f1220db8SAlexander V. Chernikov } 1083f1220db8SAlexander V. Chernikov 1084f1220db8SAlexander V. Chernikov /* 1085f1220db8SAlexander V. Chernikov * Do the actual dump in eXtended format 1086f1220db8SAlexander V. Chernikov */ 1087d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 1088f1220db8SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 1089f1220db8SAlexander V. Chernikov da.tc = tc; 10902d99a349SAlexander V. Chernikov da.sd = sd; 1091f1220db8SAlexander V. Chernikov 1092f1220db8SAlexander V. Chernikov ta = tc->ta; 1093f1220db8SAlexander V. Chernikov 109481d3153dSAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_tentry, &da); 1095f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1096f1220db8SAlexander V. Chernikov 109781d3153dSAlexander V. Chernikov return (da.error); 1098f1220db8SAlexander V. Chernikov } 1099f1220db8SAlexander V. Chernikov 1100d3a4f924SAlexander V. Chernikov /* 1101d3a4f924SAlexander V. Chernikov * Dumps all table data 11022d99a349SAlexander V. Chernikov * Data layout (version 0)(legacy): 1103d3a4f924SAlexander V. Chernikov * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE() 1104d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_xtable ipfw_table_xentry x N ] 1105d3a4f924SAlexander V. Chernikov * 1106d3a4f924SAlexander V. Chernikov * Returns 0 on success 1107d3a4f924SAlexander V. Chernikov */ 1108d3a4f924SAlexander V. Chernikov static int 11092d99a349SAlexander V. Chernikov ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd) 1110d3a4f924SAlexander V. Chernikov { 1111d3a4f924SAlexander V. Chernikov ipfw_xtable *xtbl; 1112d3a4f924SAlexander V. Chernikov struct tid_info ti; 1113d3a4f924SAlexander V. Chernikov struct table_config *tc; 1114d3a4f924SAlexander V. Chernikov struct table_algo *ta; 1115d3a4f924SAlexander V. Chernikov struct dump_args da; 1116d3a4f924SAlexander V. Chernikov size_t sz; 1117d3a4f924SAlexander V. Chernikov 11182d99a349SAlexander V. Chernikov xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable)); 11192d99a349SAlexander V. Chernikov if (xtbl == NULL) 1120d3a4f924SAlexander V. Chernikov return (EINVAL); 1121d3a4f924SAlexander V. Chernikov 1122d3a4f924SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 1123d3a4f924SAlexander V. Chernikov ti.uidx = xtbl->tbl; 1124d3a4f924SAlexander V. Chernikov 1125d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 1126d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 1127d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1128d3a4f924SAlexander V. Chernikov return (0); 1129d3a4f924SAlexander V. Chernikov } 1130d3a4f924SAlexander V. Chernikov sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); 11312d99a349SAlexander V. Chernikov 11322d99a349SAlexander V. Chernikov xtbl->cnt = tc->count; 11332d99a349SAlexander V. Chernikov xtbl->size = sz; 11342d99a349SAlexander V. Chernikov xtbl->type = tc->no.type; 11352d99a349SAlexander V. Chernikov xtbl->tbl = ti.uidx; 11362d99a349SAlexander V. Chernikov 11372d99a349SAlexander V. Chernikov if (sd->valsize < sz) { 11382d99a349SAlexander V. Chernikov 11392d99a349SAlexander V. Chernikov /* 11402d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 11412d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 11422d99a349SAlexander V. Chernikov * relevant table info including size, so we 11432d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 11442d99a349SAlexander V. Chernikov */ 1145d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 11462d99a349SAlexander V. Chernikov return (ENOMEM); 1147d3a4f924SAlexander V. Chernikov } 1148d3a4f924SAlexander V. Chernikov 1149d3a4f924SAlexander V. Chernikov /* Do the actual dump in eXtended format */ 1150d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 1151d3a4f924SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 1152d3a4f924SAlexander V. Chernikov da.tc = tc; 11532d99a349SAlexander V. Chernikov da.sd = sd; 11542d99a349SAlexander V. Chernikov 1155d3a4f924SAlexander V. Chernikov ta = tc->ta; 1156d3a4f924SAlexander V. Chernikov 1157d3a4f924SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 1158d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1159d3a4f924SAlexander V. Chernikov 11602d99a349SAlexander V. Chernikov return (0); 1161d3a4f924SAlexander V. Chernikov } 1162d3a4f924SAlexander V. Chernikov 1163d3a4f924SAlexander V. Chernikov /* 11649490a627SAlexander V. Chernikov * Creates new table. 1165ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 11669490a627SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 11679490a627SAlexander V. Chernikov * 11689490a627SAlexander V. Chernikov * Returns 0 on success 11699490a627SAlexander V. Chernikov */ 11709490a627SAlexander V. Chernikov int 1171ac35ff17SAlexander V. Chernikov ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 1172ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 11739490a627SAlexander V. Chernikov { 11749490a627SAlexander V. Chernikov struct _ipfw_obj_header *oh; 11759490a627SAlexander V. Chernikov ipfw_xtable_info *i; 11769490a627SAlexander V. Chernikov char *tname, *aname; 11779490a627SAlexander V. Chernikov struct tid_info ti; 11789490a627SAlexander V. Chernikov struct namedobj_instance *ni; 11799490a627SAlexander V. Chernikov struct table_config *tc; 11809490a627SAlexander V. Chernikov 1181ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info)) 11829490a627SAlexander V. Chernikov return (EINVAL); 11839490a627SAlexander V. Chernikov 1184ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)sd->kbuf; 11859490a627SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 11869490a627SAlexander V. Chernikov 11879490a627SAlexander V. Chernikov /* 11889490a627SAlexander V. Chernikov * Verify user-supplied strings. 11892d99a349SAlexander V. Chernikov * Check for null-terminated/zero-length strings/ 11909490a627SAlexander V. Chernikov */ 1191ac35ff17SAlexander V. Chernikov tname = oh->ntlv.name; 11929490a627SAlexander V. Chernikov aname = i->algoname; 1193ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(tname) != 0 || 11949490a627SAlexander V. Chernikov strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname)) 11959490a627SAlexander V. Chernikov return (EINVAL); 11969490a627SAlexander V. Chernikov 11979490a627SAlexander V. Chernikov if (aname[0] == '\0') { 11989490a627SAlexander V. Chernikov /* Use default algorithm */ 11999490a627SAlexander V. Chernikov aname = NULL; 12009490a627SAlexander V. Chernikov } 12019490a627SAlexander V. Chernikov 12029490a627SAlexander V. Chernikov objheader_to_ti(oh, &ti); 1203ac35ff17SAlexander V. Chernikov ti.type = i->type; 12049490a627SAlexander V. Chernikov 12059490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 12069490a627SAlexander V. Chernikov 12079490a627SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 12089490a627SAlexander V. Chernikov if ((tc = find_table(ni, &ti)) != NULL) { 12099490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 12109490a627SAlexander V. Chernikov return (EEXIST); 12119490a627SAlexander V. Chernikov } 12129490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 12139490a627SAlexander V. Chernikov 1214db785d31SAlexander V. Chernikov return (create_table_internal(ch, &ti, aname, i->vtype)); 1215db785d31SAlexander V. Chernikov } 1216db785d31SAlexander V. Chernikov 1217db785d31SAlexander V. Chernikov /* 1218db785d31SAlexander V. Chernikov * Creates new table based on @ti and @aname. 1219db785d31SAlexander V. Chernikov * 1220db785d31SAlexander V. Chernikov * Relies on table name checking inside find_name_tlv() 1221db785d31SAlexander V. Chernikov * Assume @aname to be checked and valid. 1222db785d31SAlexander V. Chernikov * 1223db785d31SAlexander V. Chernikov * Returns 0 on success. 1224db785d31SAlexander V. Chernikov */ 1225db785d31SAlexander V. Chernikov static int 1226db785d31SAlexander V. Chernikov create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, 1227db785d31SAlexander V. Chernikov char *aname, uint8_t vtype) 1228db785d31SAlexander V. Chernikov { 1229db785d31SAlexander V. Chernikov struct namedobj_instance *ni; 1230db785d31SAlexander V. Chernikov struct table_config *tc; 1231db785d31SAlexander V. Chernikov struct table_algo *ta; 1232db785d31SAlexander V. Chernikov uint16_t kidx; 1233db785d31SAlexander V. Chernikov 1234db785d31SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1235db785d31SAlexander V. Chernikov 1236db785d31SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname); 12379490a627SAlexander V. Chernikov if (ta == NULL) 12389490a627SAlexander V. Chernikov return (ENOTSUP); 12399490a627SAlexander V. Chernikov 124068394ec8SAlexander V. Chernikov if ((tc = alloc_table_config(ch, ti, ta, aname, vtype)) == NULL) 12419490a627SAlexander V. Chernikov return (ENOMEM); 12429490a627SAlexander V. Chernikov 12439490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1244db785d31SAlexander V. Chernikov 1245db785d31SAlexander V. Chernikov /* Check if table has been already created */ 1246db785d31SAlexander V. Chernikov if (find_table(ni, ti) != NULL) { 1247db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1248db785d31SAlexander V. Chernikov free_table_config(ni, tc); 1249db785d31SAlexander V. Chernikov return (EEXIST); 1250db785d31SAlexander V. Chernikov } 1251db785d31SAlexander V. Chernikov 1252ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) { 12539490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1254db785d31SAlexander V. Chernikov printf("Unable to allocate table index." 1255db785d31SAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max"); 12569490a627SAlexander V. Chernikov free_table_config(ni, tc); 12579490a627SAlexander V. Chernikov return (EBUSY); 12589490a627SAlexander V. Chernikov } 12599490a627SAlexander V. Chernikov 12609490a627SAlexander V. Chernikov tc->no.kidx = kidx; 12619490a627SAlexander V. Chernikov 12629490a627SAlexander V. Chernikov IPFW_WLOCK(ch); 12639490a627SAlexander V. Chernikov link_table(ch, tc); 12649490a627SAlexander V. Chernikov IPFW_WUNLOCK(ch); 12659490a627SAlexander V. Chernikov 12669490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 12679490a627SAlexander V. Chernikov 12689490a627SAlexander V. Chernikov return (0); 12699490a627SAlexander V. Chernikov } 12709490a627SAlexander V. Chernikov 1271d3a4f924SAlexander V. Chernikov void 1272d3a4f924SAlexander V. Chernikov objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti) 1273d3a4f924SAlexander V. Chernikov { 1274d3a4f924SAlexander V. Chernikov 1275d3a4f924SAlexander V. Chernikov memset(ti, 0, sizeof(struct tid_info)); 127681d3153dSAlexander V. Chernikov ti->set = oh->ntlv.set; 1277d3a4f924SAlexander V. Chernikov ti->uidx = oh->idx; 1278d3a4f924SAlexander V. Chernikov ti->tlvs = &oh->ntlv; 1279d3a4f924SAlexander V. Chernikov ti->tlen = oh->ntlv.head.length; 1280d3a4f924SAlexander V. Chernikov } 1281d3a4f924SAlexander V. Chernikov 1282563b5ab1SAlexander V. Chernikov int 1283563b5ab1SAlexander V. Chernikov ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx, 1284563b5ab1SAlexander V. Chernikov struct sockopt_data *sd) 1285563b5ab1SAlexander V. Chernikov { 1286563b5ab1SAlexander V. Chernikov struct namedobj_instance *ni; 1287563b5ab1SAlexander V. Chernikov struct named_object *no; 1288563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1289563b5ab1SAlexander V. Chernikov 1290563b5ab1SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1291563b5ab1SAlexander V. Chernikov 1292ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 1293563b5ab1SAlexander V. Chernikov KASSERT(no != NULL, ("invalid table kidx passed")); 1294563b5ab1SAlexander V. Chernikov 1295563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 1296563b5ab1SAlexander V. Chernikov if (ntlv == NULL) 1297563b5ab1SAlexander V. Chernikov return (ENOMEM); 1298563b5ab1SAlexander V. Chernikov 1299563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 1300563b5ab1SAlexander V. Chernikov ntlv->head.length = sizeof(*ntlv); 1301563b5ab1SAlexander V. Chernikov ntlv->idx = no->kidx; 1302563b5ab1SAlexander V. Chernikov strlcpy(ntlv->name, no->name, sizeof(ntlv->name)); 1303563b5ab1SAlexander V. Chernikov 1304563b5ab1SAlexander V. Chernikov return (0); 1305563b5ab1SAlexander V. Chernikov } 1306563b5ab1SAlexander V. Chernikov 13079f7d47b0SAlexander V. Chernikov static void 1308ac35ff17SAlexander V. Chernikov export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 1309ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i) 13109f7d47b0SAlexander V. Chernikov { 1311ac35ff17SAlexander V. Chernikov struct table_info *ti; 13129f7d47b0SAlexander V. Chernikov 13139f7d47b0SAlexander V. Chernikov i->type = tc->no.type; 1314ac35ff17SAlexander V. Chernikov i->vtype = tc->vtype; 13159f7d47b0SAlexander V. Chernikov i->set = tc->no.set; 13169f7d47b0SAlexander V. Chernikov i->kidx = tc->no.kidx; 13179f7d47b0SAlexander V. Chernikov i->refcnt = tc->no.refcnt; 13189f7d47b0SAlexander V. Chernikov i->count = tc->count; 131981d3153dSAlexander V. Chernikov i->size = tc->count * sizeof(ipfw_obj_tentry); 1320f1220db8SAlexander V. Chernikov i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 13219f7d47b0SAlexander V. Chernikov strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); 1322ac35ff17SAlexander V. Chernikov if (tc->ta->print_config != NULL) { 1323ac35ff17SAlexander V. Chernikov /* Use algo function to print table config to string */ 1324ac35ff17SAlexander V. Chernikov ti = KIDX_TO_TI(ch, tc->no.kidx); 1325ac35ff17SAlexander V. Chernikov tc->ta->print_config(tc->astate, ti, i->algoname, 1326ac35ff17SAlexander V. Chernikov sizeof(i->algoname)); 1327ac35ff17SAlexander V. Chernikov } else 1328ac35ff17SAlexander V. Chernikov strlcpy(i->algoname, tc->ta->name, sizeof(i->algoname)); 13299f7d47b0SAlexander V. Chernikov } 13309f7d47b0SAlexander V. Chernikov 1331ac35ff17SAlexander V. Chernikov struct dump_table_args { 1332ac35ff17SAlexander V. Chernikov struct ip_fw_chain *ch; 1333ac35ff17SAlexander V. Chernikov struct sockopt_data *sd; 1334ac35ff17SAlexander V. Chernikov }; 1335ac35ff17SAlexander V. Chernikov 13369f7d47b0SAlexander V. Chernikov static void 13379f7d47b0SAlexander V. Chernikov export_table_internal(struct namedobj_instance *ni, struct named_object *no, 13389f7d47b0SAlexander V. Chernikov void *arg) 13393b3a8eb9SGleb Smirnoff { 13409f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i; 1341ac35ff17SAlexander V. Chernikov struct dump_table_args *dta; 13423b3a8eb9SGleb Smirnoff 1343ac35ff17SAlexander V. Chernikov dta = (struct dump_table_args *)arg; 1344ac35ff17SAlexander V. Chernikov 1345ac35ff17SAlexander V. Chernikov i = (ipfw_xtable_info *)ipfw_get_sopt_space(dta->sd, sizeof(*i)); 134668394ec8SAlexander V. Chernikov KASSERT(i != 0, ("previously checked buffer is not enough")); 13479f7d47b0SAlexander V. Chernikov 1348ac35ff17SAlexander V. Chernikov export_table_info(dta->ch, (struct table_config *)no, i); 13499f7d47b0SAlexander V. Chernikov } 13509f7d47b0SAlexander V. Chernikov 1351f1220db8SAlexander V. Chernikov /* 1352f1220db8SAlexander V. Chernikov * Export all tables as ipfw_xtable_info structures to 13532d99a349SAlexander V. Chernikov * storage provided by @sd. 1354f1220db8SAlexander V. Chernikov * Returns 0 on success. 1355f1220db8SAlexander V. Chernikov */ 1356f1220db8SAlexander V. Chernikov static int 13572d99a349SAlexander V. Chernikov export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 13582d99a349SAlexander V. Chernikov struct sockopt_data *sd) 13599f7d47b0SAlexander V. Chernikov { 13609f7d47b0SAlexander V. Chernikov uint32_t size; 13619f7d47b0SAlexander V. Chernikov uint32_t count; 1362ac35ff17SAlexander V. Chernikov struct dump_table_args dta; 13639f7d47b0SAlexander V. Chernikov 13649f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 13659f7d47b0SAlexander V. Chernikov size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 13662d99a349SAlexander V. Chernikov 13672d99a349SAlexander V. Chernikov /* Fill in header regadless of buffer size */ 1368f1220db8SAlexander V. Chernikov olh->count = count; 1369f1220db8SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 13702d99a349SAlexander V. Chernikov 13712d99a349SAlexander V. Chernikov if (size > olh->size) { 13722d99a349SAlexander V. Chernikov olh->size = size; 13739f7d47b0SAlexander V. Chernikov return (ENOMEM); 1374f1220db8SAlexander V. Chernikov } 137568394ec8SAlexander V. Chernikov 13769f7d47b0SAlexander V. Chernikov olh->size = size; 13772d99a349SAlexander V. Chernikov 1378ac35ff17SAlexander V. Chernikov dta.ch = ch; 1379ac35ff17SAlexander V. Chernikov dta.sd = sd; 1380ac35ff17SAlexander V. Chernikov 1381ac35ff17SAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, &dta); 13829f7d47b0SAlexander V. Chernikov 13833b3a8eb9SGleb Smirnoff return (0); 13843b3a8eb9SGleb Smirnoff } 13853b3a8eb9SGleb Smirnoff 138681d3153dSAlexander V. Chernikov /* 138781d3153dSAlexander V. Chernikov * Legacy IP_FW_TABLE_GETSIZE handler 138881d3153dSAlexander V. Chernikov */ 13893b3a8eb9SGleb Smirnoff int 1390b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 13913b3a8eb9SGleb Smirnoff { 1392b074b7bbSAlexander V. Chernikov struct table_config *tc; 13933b3a8eb9SGleb Smirnoff 1394b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1395b074b7bbSAlexander V. Chernikov return (ESRCH); 13969f7d47b0SAlexander V. Chernikov *cnt = tc->count; 13973b3a8eb9SGleb Smirnoff return (0); 13983b3a8eb9SGleb Smirnoff } 13993b3a8eb9SGleb Smirnoff 14009f7d47b0SAlexander V. Chernikov 140181d3153dSAlexander V. Chernikov /* 140281d3153dSAlexander V. Chernikov * Legacy IP_FW_TABLE_XGETSIZE handler 140381d3153dSAlexander V. Chernikov */ 14049f7d47b0SAlexander V. Chernikov int 14059f7d47b0SAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 14063b3a8eb9SGleb Smirnoff { 14079f7d47b0SAlexander V. Chernikov struct table_config *tc; 14089f7d47b0SAlexander V. Chernikov 1409d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) { 1410d3a4f924SAlexander V. Chernikov *cnt = 0; 14119f7d47b0SAlexander V. Chernikov return (0); /* 'table all list' requires success */ 1412d3a4f924SAlexander V. Chernikov } 14139f7d47b0SAlexander V. Chernikov *cnt = tc->count * sizeof(ipfw_table_xentry); 14149f7d47b0SAlexander V. Chernikov if (tc->count > 0) 14159f7d47b0SAlexander V. Chernikov *cnt += sizeof(ipfw_xtable); 14169f7d47b0SAlexander V. Chernikov return (0); 14179f7d47b0SAlexander V. Chernikov } 14189f7d47b0SAlexander V. Chernikov 14199f7d47b0SAlexander V. Chernikov static int 14209f7d47b0SAlexander V. Chernikov dump_table_entry(void *e, void *arg) 14219f7d47b0SAlexander V. Chernikov { 14229f7d47b0SAlexander V. Chernikov struct dump_args *da; 14239f7d47b0SAlexander V. Chernikov struct table_config *tc; 14249f7d47b0SAlexander V. Chernikov struct table_algo *ta; 14253b3a8eb9SGleb Smirnoff ipfw_table_entry *ent; 142681d3153dSAlexander V. Chernikov int error; 14273b3a8eb9SGleb Smirnoff 14289f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 14299f7d47b0SAlexander V. Chernikov 14309f7d47b0SAlexander V. Chernikov tc = da->tc; 14319f7d47b0SAlexander V. Chernikov ta = tc->ta; 14329f7d47b0SAlexander V. Chernikov 14339f7d47b0SAlexander V. Chernikov /* Out of memory, returning */ 1434f1220db8SAlexander V. Chernikov if (da->cnt == da->size) 14353b3a8eb9SGleb Smirnoff return (1); 1436f1220db8SAlexander V. Chernikov ent = da->ent++; 1437f1220db8SAlexander V. Chernikov ent->tbl = da->uidx; 1438f1220db8SAlexander V. Chernikov da->cnt++; 14399f7d47b0SAlexander V. Chernikov 144081d3153dSAlexander V. Chernikov error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent); 144181d3153dSAlexander V. Chernikov if (error != 0) 144281d3153dSAlexander V. Chernikov return (error); 144381d3153dSAlexander V. Chernikov 144481d3153dSAlexander V. Chernikov ent->addr = da->tent.k.addr.s_addr; 144581d3153dSAlexander V. Chernikov ent->masklen = da->tent.masklen; 144681d3153dSAlexander V. Chernikov ent->value = da->tent.value; 144781d3153dSAlexander V. Chernikov 144881d3153dSAlexander V. Chernikov return (0); 14493b3a8eb9SGleb Smirnoff } 14503b3a8eb9SGleb Smirnoff 1451f1220db8SAlexander V. Chernikov /* 1452f1220db8SAlexander V. Chernikov * Dumps table in pre-8.1 legacy format. 1453f1220db8SAlexander V. Chernikov */ 14543b3a8eb9SGleb Smirnoff int 1455f1220db8SAlexander V. Chernikov ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti, 1456f1220db8SAlexander V. Chernikov ipfw_table *tbl) 14573b3a8eb9SGleb Smirnoff { 1458b074b7bbSAlexander V. Chernikov struct table_config *tc; 14599f7d47b0SAlexander V. Chernikov struct table_algo *ta; 14609f7d47b0SAlexander V. Chernikov struct dump_args da; 14613b3a8eb9SGleb Smirnoff 14623b3a8eb9SGleb Smirnoff tbl->cnt = 0; 14633b3a8eb9SGleb Smirnoff 1464b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1465b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 14669f7d47b0SAlexander V. Chernikov 14679f7d47b0SAlexander V. Chernikov ta = tc->ta; 14689f7d47b0SAlexander V. Chernikov 146981d3153dSAlexander V. Chernikov /* This dump format supports IPv4 only */ 147081d3153dSAlexander V. Chernikov if (tc->no.type != IPFW_TABLE_CIDR) 147181d3153dSAlexander V. Chernikov return (0); 14729f7d47b0SAlexander V. Chernikov 1473d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 14749f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 14759f7d47b0SAlexander V. Chernikov da.tc = tc; 1476f1220db8SAlexander V. Chernikov da.ent = &tbl->ent[0]; 1477f1220db8SAlexander V. Chernikov da.size = tbl->size; 14789f7d47b0SAlexander V. Chernikov 14799f7d47b0SAlexander V. Chernikov tbl->cnt = 0; 14809f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_entry, &da); 1481f1220db8SAlexander V. Chernikov tbl->cnt = da.cnt; 14829f7d47b0SAlexander V. Chernikov 14833b3a8eb9SGleb Smirnoff return (0); 14843b3a8eb9SGleb Smirnoff } 14853b3a8eb9SGleb Smirnoff 14869490a627SAlexander V. Chernikov /* 148781d3153dSAlexander V. Chernikov * Dumps table entry in eXtended format (v1)(current). 148881d3153dSAlexander V. Chernikov */ 148981d3153dSAlexander V. Chernikov static int 149081d3153dSAlexander V. Chernikov dump_table_tentry(void *e, void *arg) 149181d3153dSAlexander V. Chernikov { 149281d3153dSAlexander V. Chernikov struct dump_args *da; 149381d3153dSAlexander V. Chernikov struct table_config *tc; 149481d3153dSAlexander V. Chernikov struct table_algo *ta; 149581d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 149681d3153dSAlexander V. Chernikov 149781d3153dSAlexander V. Chernikov da = (struct dump_args *)arg; 149881d3153dSAlexander V. Chernikov 149981d3153dSAlexander V. Chernikov tc = da->tc; 150081d3153dSAlexander V. Chernikov ta = tc->ta; 150181d3153dSAlexander V. Chernikov 150281d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent)); 150381d3153dSAlexander V. Chernikov /* Out of memory, returning */ 150481d3153dSAlexander V. Chernikov if (tent == NULL) { 150581d3153dSAlexander V. Chernikov da->error = ENOMEM; 150681d3153dSAlexander V. Chernikov return (1); 150781d3153dSAlexander V. Chernikov } 150881d3153dSAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 150981d3153dSAlexander V. Chernikov tent->idx = da->uidx; 151081d3153dSAlexander V. Chernikov 151181d3153dSAlexander V. Chernikov return (ta->dump_tentry(tc->astate, da->ti, e, tent)); 151281d3153dSAlexander V. Chernikov } 151381d3153dSAlexander V. Chernikov 151481d3153dSAlexander V. Chernikov /* 151581d3153dSAlexander V. Chernikov * Dumps table entry in eXtended format (v0). 15169490a627SAlexander V. Chernikov */ 15173b3a8eb9SGleb Smirnoff static int 15189f7d47b0SAlexander V. Chernikov dump_table_xentry(void *e, void *arg) 15193b3a8eb9SGleb Smirnoff { 15209f7d47b0SAlexander V. Chernikov struct dump_args *da; 15219f7d47b0SAlexander V. Chernikov struct table_config *tc; 15229f7d47b0SAlexander V. Chernikov struct table_algo *ta; 15233b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 152481d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 152581d3153dSAlexander V. Chernikov int error; 15263b3a8eb9SGleb Smirnoff 15279f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 15289f7d47b0SAlexander V. Chernikov 15299f7d47b0SAlexander V. Chernikov tc = da->tc; 15309f7d47b0SAlexander V. Chernikov ta = tc->ta; 15319f7d47b0SAlexander V. Chernikov 15322d99a349SAlexander V. Chernikov xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent)); 15333b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 15342d99a349SAlexander V. Chernikov if (xent == NULL) 15353b3a8eb9SGleb Smirnoff return (1); 15363b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 1537f1220db8SAlexander V. Chernikov xent->tbl = da->uidx; 15389f7d47b0SAlexander V. Chernikov 153981d3153dSAlexander V. Chernikov memset(&da->tent, 0, sizeof(da->tent)); 154081d3153dSAlexander V. Chernikov tent = &da->tent; 154181d3153dSAlexander V. Chernikov error = ta->dump_tentry(tc->astate, da->ti, e, tent); 154281d3153dSAlexander V. Chernikov if (error != 0) 154381d3153dSAlexander V. Chernikov return (error); 154481d3153dSAlexander V. Chernikov 154581d3153dSAlexander V. Chernikov /* Convert current format to previous one */ 154681d3153dSAlexander V. Chernikov xent->masklen = tent->masklen; 154781d3153dSAlexander V. Chernikov xent->value = tent->value; 154881d3153dSAlexander V. Chernikov /* Apply some hacks */ 154981d3153dSAlexander V. Chernikov if (tc->no.type == IPFW_TABLE_CIDR && tent->subtype == AF_INET) { 155081d3153dSAlexander V. Chernikov xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr; 155181d3153dSAlexander V. Chernikov xent->flags = IPFW_TCF_INET; 155281d3153dSAlexander V. Chernikov } else 155381d3153dSAlexander V. Chernikov memcpy(&xent->k, &tent->k, sizeof(xent->k)); 155481d3153dSAlexander V. Chernikov 155581d3153dSAlexander V. Chernikov return (0); 15569f7d47b0SAlexander V. Chernikov } 15579f7d47b0SAlexander V. Chernikov 15589f7d47b0SAlexander V. Chernikov /* 15599f7d47b0SAlexander V. Chernikov * Table algorithms 15609f7d47b0SAlexander V. Chernikov */ 15613b3a8eb9SGleb Smirnoff 15629f7d47b0SAlexander V. Chernikov /* 15639490a627SAlexander V. Chernikov * Finds algoritm by index, table type or supplied name 15649f7d47b0SAlexander V. Chernikov */ 15659f7d47b0SAlexander V. Chernikov static struct table_algo * 15669490a627SAlexander V. Chernikov find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name) 15679f7d47b0SAlexander V. Chernikov { 15689490a627SAlexander V. Chernikov int i, l; 15699490a627SAlexander V. Chernikov struct table_algo *ta; 15709f7d47b0SAlexander V. Chernikov 15719f7d47b0SAlexander V. Chernikov /* Search by index */ 15729f7d47b0SAlexander V. Chernikov if (ti->atype != 0) { 15739f7d47b0SAlexander V. Chernikov if (ti->atype > tcfg->algo_count) 15749f7d47b0SAlexander V. Chernikov return (NULL); 15759f7d47b0SAlexander V. Chernikov return (tcfg->algo[ti->atype]); 15769f7d47b0SAlexander V. Chernikov } 15779f7d47b0SAlexander V. Chernikov 15789490a627SAlexander V. Chernikov /* Search by name if supplied */ 15799490a627SAlexander V. Chernikov if (name != NULL) { 15809490a627SAlexander V. Chernikov /* TODO: better search */ 15819490a627SAlexander V. Chernikov for (i = 1; i <= tcfg->algo_count; i++) { 15829490a627SAlexander V. Chernikov ta = tcfg->algo[i]; 15839490a627SAlexander V. Chernikov 15849490a627SAlexander V. Chernikov /* 15859490a627SAlexander V. Chernikov * One can supply additional algorithm 15869490a627SAlexander V. Chernikov * parameters so we compare only the first word 15879490a627SAlexander V. Chernikov * of supplied name: 15889490a627SAlexander V. Chernikov * 'hash_cidr hsize=32' 15899490a627SAlexander V. Chernikov * '^^^^^^^^^' 15909490a627SAlexander V. Chernikov * 15919490a627SAlexander V. Chernikov */ 15929490a627SAlexander V. Chernikov l = strlen(ta->name); 15939490a627SAlexander V. Chernikov if (strncmp(name, ta->name, l) == 0) { 15949490a627SAlexander V. Chernikov if (name[l] == '\0' || name[l] == ' ') 15959490a627SAlexander V. Chernikov return (ta); 15969490a627SAlexander V. Chernikov } 15979490a627SAlexander V. Chernikov } 15989490a627SAlexander V. Chernikov 15999490a627SAlexander V. Chernikov return (NULL); 16009490a627SAlexander V. Chernikov } 16019490a627SAlexander V. Chernikov 16029f7d47b0SAlexander V. Chernikov /* Search by type */ 16039f7d47b0SAlexander V. Chernikov switch (ti->type) { 16043b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 160574b941f0SAlexander V. Chernikov return (&cidr_radix); 16063b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 160774b941f0SAlexander V. Chernikov return (&iface_idx); 16083b3a8eb9SGleb Smirnoff } 16093b3a8eb9SGleb Smirnoff 16109f7d47b0SAlexander V. Chernikov return (NULL); 16113b3a8eb9SGleb Smirnoff } 16123b3a8eb9SGleb Smirnoff 16130b565ac0SAlexander V. Chernikov int 16140b565ac0SAlexander V. Chernikov ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta, size_t size, 16150b565ac0SAlexander V. Chernikov int *idx) 16163b3a8eb9SGleb Smirnoff { 16179f7d47b0SAlexander V. Chernikov struct tables_config *tcfg; 16180b565ac0SAlexander V. Chernikov struct table_algo *ta_new; 16190b565ac0SAlexander V. Chernikov 16200b565ac0SAlexander V. Chernikov if (size > sizeof(struct table_algo)) 16210b565ac0SAlexander V. Chernikov return (EINVAL); 16220b565ac0SAlexander V. Chernikov 16230b565ac0SAlexander V. Chernikov ta_new = malloc(sizeof(struct table_algo), M_IPFW, M_WAITOK | M_ZERO); 16240b565ac0SAlexander V. Chernikov memcpy(ta_new, ta, size); 16253b3a8eb9SGleb Smirnoff 16269f7d47b0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 1627b074b7bbSAlexander V. Chernikov 16289f7d47b0SAlexander V. Chernikov KASSERT(tcfg->algo_count < 255, ("Increase algo array size")); 16299f7d47b0SAlexander V. Chernikov 16300b565ac0SAlexander V. Chernikov tcfg->algo[++tcfg->algo_count] = ta_new; 16310b565ac0SAlexander V. Chernikov ta_new->idx = tcfg->algo_count; 16320b565ac0SAlexander V. Chernikov 16330b565ac0SAlexander V. Chernikov *idx = ta_new->idx; 16340b565ac0SAlexander V. Chernikov 16350b565ac0SAlexander V. Chernikov return (0); 16360b565ac0SAlexander V. Chernikov } 16370b565ac0SAlexander V. Chernikov 16380b565ac0SAlexander V. Chernikov void 16390b565ac0SAlexander V. Chernikov ipfw_del_table_algo(struct ip_fw_chain *ch, int idx) 16400b565ac0SAlexander V. Chernikov { 16410b565ac0SAlexander V. Chernikov struct tables_config *tcfg; 16420b565ac0SAlexander V. Chernikov struct table_algo *ta; 16430b565ac0SAlexander V. Chernikov 16440b565ac0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 16450b565ac0SAlexander V. Chernikov 16460b565ac0SAlexander V. Chernikov KASSERT(idx <= tcfg->algo_count, ("algo idx %d out of rage 1..%d", idx, 16470b565ac0SAlexander V. Chernikov tcfg->algo_count)); 16480b565ac0SAlexander V. Chernikov 16490b565ac0SAlexander V. Chernikov ta = tcfg->algo[idx]; 16500b565ac0SAlexander V. Chernikov KASSERT(ta != NULL, ("algo idx %d is NULL", idx)); 16510b565ac0SAlexander V. Chernikov free(ta, M_IPFW); 16523b3a8eb9SGleb Smirnoff } 16533b3a8eb9SGleb Smirnoff 16549d099b4fSAlexander V. Chernikov /* 16559d099b4fSAlexander V. Chernikov * Lists all table algorithms currently available. 16569d099b4fSAlexander V. Chernikov * Data layout (v0)(current): 16579d099b4fSAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 16589d099b4fSAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_ta_info x N ] 16599d099b4fSAlexander V. Chernikov * 16609d099b4fSAlexander V. Chernikov * Returns 0 on success 16619d099b4fSAlexander V. Chernikov */ 16629d099b4fSAlexander V. Chernikov int 16639d099b4fSAlexander V. Chernikov ipfw_list_table_algo(struct ip_fw_chain *ch, struct sockopt_data *sd) 16649d099b4fSAlexander V. Chernikov { 16659d099b4fSAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 16669d099b4fSAlexander V. Chernikov struct tables_config *tcfg; 16679d099b4fSAlexander V. Chernikov ipfw_ta_info *i; 16689d099b4fSAlexander V. Chernikov struct table_algo *ta; 16699d099b4fSAlexander V. Chernikov uint32_t count, n, size; 16709d099b4fSAlexander V. Chernikov 16719d099b4fSAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 16729d099b4fSAlexander V. Chernikov if (olh == NULL) 16739d099b4fSAlexander V. Chernikov return (EINVAL); 16749d099b4fSAlexander V. Chernikov if (sd->valsize < olh->size) 16759d099b4fSAlexander V. Chernikov return (EINVAL); 16769d099b4fSAlexander V. Chernikov 16779d099b4fSAlexander V. Chernikov IPFW_UH_RLOCK(ch); 16789d099b4fSAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 16799d099b4fSAlexander V. Chernikov count = tcfg->algo_count; 16809d099b4fSAlexander V. Chernikov size = count * sizeof(ipfw_ta_info) + sizeof(ipfw_obj_lheader); 16819d099b4fSAlexander V. Chernikov 16829d099b4fSAlexander V. Chernikov /* Fill in header regadless of buffer size */ 16839d099b4fSAlexander V. Chernikov olh->count = count; 16849d099b4fSAlexander V. Chernikov olh->objsize = sizeof(ipfw_ta_info); 16859d099b4fSAlexander V. Chernikov 16869d099b4fSAlexander V. Chernikov if (size > olh->size) { 16879d099b4fSAlexander V. Chernikov olh->size = size; 16889d099b4fSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 16899d099b4fSAlexander V. Chernikov return (ENOMEM); 16909d099b4fSAlexander V. Chernikov } 16919d099b4fSAlexander V. Chernikov olh->size = size; 16929d099b4fSAlexander V. Chernikov 16939d099b4fSAlexander V. Chernikov for (n = 1; n <= count; n++) { 16949d099b4fSAlexander V. Chernikov i = (ipfw_ta_info *)ipfw_get_sopt_space(sd, sizeof(*i)); 16959d099b4fSAlexander V. Chernikov KASSERT(i != 0, ("previously checked buffer is not enough")); 16969d099b4fSAlexander V. Chernikov ta = tcfg->algo[n]; 16979d099b4fSAlexander V. Chernikov strlcpy(i->algoname, ta->name, sizeof(i->algoname)); 16989d099b4fSAlexander V. Chernikov i->type = ta->type; 16999d099b4fSAlexander V. Chernikov i->refcnt = ta->refcnt; 17009d099b4fSAlexander V. Chernikov } 17019d099b4fSAlexander V. Chernikov 17029d099b4fSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 17039d099b4fSAlexander V. Chernikov 17049d099b4fSAlexander V. Chernikov return (0); 17059d099b4fSAlexander V. Chernikov } 17069d099b4fSAlexander V. Chernikov 17079f7d47b0SAlexander V. Chernikov 1708b074b7bbSAlexander V. Chernikov /* 1709b074b7bbSAlexander V. Chernikov * Tables rewriting code 1710b074b7bbSAlexander V. Chernikov * 1711b074b7bbSAlexander V. Chernikov */ 1712b074b7bbSAlexander V. Chernikov 1713b074b7bbSAlexander V. Chernikov /* 1714b074b7bbSAlexander V. Chernikov * Determine table number and lookup type for @cmd. 1715b074b7bbSAlexander V. Chernikov * Fill @tbl and @type with appropriate values. 1716b074b7bbSAlexander V. Chernikov * Returns 0 for relevant opcodes, 1 otherwise. 1717b074b7bbSAlexander V. Chernikov */ 1718b074b7bbSAlexander V. Chernikov static int 1719b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 1720b074b7bbSAlexander V. Chernikov { 1721b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1722b074b7bbSAlexander V. Chernikov int skip; 1723b074b7bbSAlexander V. Chernikov uint16_t v; 1724b074b7bbSAlexander V. Chernikov 1725b074b7bbSAlexander V. Chernikov skip = 1; 1726b074b7bbSAlexander V. Chernikov 1727b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1728b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1729b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1730b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1731b074b7bbSAlexander V. Chernikov *puidx = cmd->arg1; 1732b074b7bbSAlexander V. Chernikov /* Assume CIDR by default */ 1733b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 1734b074b7bbSAlexander V. Chernikov skip = 0; 1735b074b7bbSAlexander V. Chernikov 1736b074b7bbSAlexander V. Chernikov if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { 1737b074b7bbSAlexander V. Chernikov /* 1738b074b7bbSAlexander V. Chernikov * generic lookup. The key must be 1739b074b7bbSAlexander V. Chernikov * in 32bit big-endian format. 1740b074b7bbSAlexander V. Chernikov */ 1741b074b7bbSAlexander V. Chernikov v = ((ipfw_insn_u32 *)cmd)->d[1]; 1742b074b7bbSAlexander V. Chernikov switch (v) { 1743b074b7bbSAlexander V. Chernikov case 0: 1744b074b7bbSAlexander V. Chernikov case 1: 1745b074b7bbSAlexander V. Chernikov /* IPv4 src/dst */ 1746b074b7bbSAlexander V. Chernikov break; 1747b074b7bbSAlexander V. Chernikov case 2: 1748b074b7bbSAlexander V. Chernikov case 3: 1749b074b7bbSAlexander V. Chernikov /* src/dst port */ 1750b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1751b074b7bbSAlexander V. Chernikov break; 1752b074b7bbSAlexander V. Chernikov case 4: 1753b074b7bbSAlexander V. Chernikov /* uid/gid */ 1754b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1755b23d5de9SAlexander V. Chernikov break; 1756b074b7bbSAlexander V. Chernikov case 5: 1757b074b7bbSAlexander V. Chernikov /* jid */ 1758b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1759b23d5de9SAlexander V. Chernikov break; 1760b074b7bbSAlexander V. Chernikov case 6: 1761b074b7bbSAlexander V. Chernikov /* dscp */ 1762b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1763b074b7bbSAlexander V. Chernikov break; 1764b074b7bbSAlexander V. Chernikov } 1765b074b7bbSAlexander V. Chernikov } 1766b074b7bbSAlexander V. Chernikov break; 1767b074b7bbSAlexander V. Chernikov case O_XMIT: 1768b074b7bbSAlexander V. Chernikov case O_RECV: 1769b074b7bbSAlexander V. Chernikov case O_VIA: 1770b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1771b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1772b074b7bbSAlexander V. Chernikov if (cmdif->name[0] != '\1') 1773b074b7bbSAlexander V. Chernikov break; 1774b074b7bbSAlexander V. Chernikov 1775b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 1776b074b7bbSAlexander V. Chernikov *puidx = cmdif->p.glob; 1777b074b7bbSAlexander V. Chernikov skip = 0; 1778b074b7bbSAlexander V. Chernikov break; 1779b074b7bbSAlexander V. Chernikov } 1780b074b7bbSAlexander V. Chernikov 1781b074b7bbSAlexander V. Chernikov return (skip); 1782b074b7bbSAlexander V. Chernikov } 1783b074b7bbSAlexander V. Chernikov 1784b074b7bbSAlexander V. Chernikov /* 1785b074b7bbSAlexander V. Chernikov * Sets new table value for given opcode. 1786b074b7bbSAlexander V. Chernikov * Assume the same opcodes as classify_table_opcode() 1787b074b7bbSAlexander V. Chernikov */ 1788b074b7bbSAlexander V. Chernikov static void 1789b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx) 1790b074b7bbSAlexander V. Chernikov { 1791b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1792b074b7bbSAlexander V. Chernikov 1793b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1794b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1795b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1796b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1797b074b7bbSAlexander V. Chernikov cmd->arg1 = idx; 1798b074b7bbSAlexander V. Chernikov break; 1799b074b7bbSAlexander V. Chernikov case O_XMIT: 1800b074b7bbSAlexander V. Chernikov case O_RECV: 1801b074b7bbSAlexander V. Chernikov case O_VIA: 1802b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1803b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1804b074b7bbSAlexander V. Chernikov cmdif->p.glob = idx; 1805b074b7bbSAlexander V. Chernikov break; 1806b074b7bbSAlexander V. Chernikov } 1807b074b7bbSAlexander V. Chernikov } 1808b074b7bbSAlexander V. Chernikov 1809ac35ff17SAlexander V. Chernikov /* 1810ac35ff17SAlexander V. Chernikov * Checks table name for validity. 1811ac35ff17SAlexander V. Chernikov * Enforce basic length checks, the rest 1812ac35ff17SAlexander V. Chernikov * should be done in userland. 1813ac35ff17SAlexander V. Chernikov * 1814ac35ff17SAlexander V. Chernikov * Returns 0 if name is considered valid. 1815ac35ff17SAlexander V. Chernikov */ 1816ac35ff17SAlexander V. Chernikov int 1817ac35ff17SAlexander V. Chernikov ipfw_check_table_name(char *name) 1818ac35ff17SAlexander V. Chernikov { 1819ac35ff17SAlexander V. Chernikov int nsize; 1820ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv = NULL; 1821ac35ff17SAlexander V. Chernikov 1822ac35ff17SAlexander V. Chernikov nsize = sizeof(ntlv->name); 1823ac35ff17SAlexander V. Chernikov 1824ac35ff17SAlexander V. Chernikov if (strnlen(name, nsize) == nsize) 1825ac35ff17SAlexander V. Chernikov return (EINVAL); 1826ac35ff17SAlexander V. Chernikov 1827ac35ff17SAlexander V. Chernikov if (name[0] == '\0') 1828ac35ff17SAlexander V. Chernikov return (EINVAL); 1829ac35ff17SAlexander V. Chernikov 1830ac35ff17SAlexander V. Chernikov /* 1831ac35ff17SAlexander V. Chernikov * TODO: do some more complicated checks 1832ac35ff17SAlexander V. Chernikov */ 1833ac35ff17SAlexander V. Chernikov 1834ac35ff17SAlexander V. Chernikov return (0); 1835ac35ff17SAlexander V. Chernikov } 1836ac35ff17SAlexander V. Chernikov 1837ac35ff17SAlexander V. Chernikov /* 1838ac35ff17SAlexander V. Chernikov * Find tablename TLV by @uid. 1839ac35ff17SAlexander V. Chernikov * Check @tlvs for valid data inside. 1840ac35ff17SAlexander V. Chernikov * 1841ac35ff17SAlexander V. Chernikov * Returns pointer to found TLV or NULL. 1842ac35ff17SAlexander V. Chernikov */ 1843ac35ff17SAlexander V. Chernikov static ipfw_obj_ntlv * 1844b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx) 1845b074b7bbSAlexander V. Chernikov { 18469f7d47b0SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1847b074b7bbSAlexander V. Chernikov uintptr_t pa, pe; 1848b074b7bbSAlexander V. Chernikov int l; 1849b074b7bbSAlexander V. Chernikov 1850b074b7bbSAlexander V. Chernikov pa = (uintptr_t)tlvs; 1851b074b7bbSAlexander V. Chernikov pe = pa + len; 1852b074b7bbSAlexander V. Chernikov l = 0; 1853b074b7bbSAlexander V. Chernikov for (; pa < pe; pa += l) { 18549f7d47b0SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)pa; 1855b074b7bbSAlexander V. Chernikov l = ntlv->head.length; 1856ac35ff17SAlexander V. Chernikov 1857ac35ff17SAlexander V. Chernikov if (l != sizeof(*ntlv)) 1858ac35ff17SAlexander V. Chernikov return (NULL); 1859ac35ff17SAlexander V. Chernikov 1860563b5ab1SAlexander V. Chernikov if (ntlv->head.type != IPFW_TLV_TBL_NAME) 1861b074b7bbSAlexander V. Chernikov continue; 1862ac35ff17SAlexander V. Chernikov 1863b074b7bbSAlexander V. Chernikov if (ntlv->idx != uidx) 1864b074b7bbSAlexander V. Chernikov continue; 1865b074b7bbSAlexander V. Chernikov 1866ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(ntlv->name) != 0) 1867ac35ff17SAlexander V. Chernikov return (NULL); 1868ac35ff17SAlexander V. Chernikov 1869ac35ff17SAlexander V. Chernikov return (ntlv); 1870b074b7bbSAlexander V. Chernikov } 1871b074b7bbSAlexander V. Chernikov 1872b074b7bbSAlexander V. Chernikov return (NULL); 1873b074b7bbSAlexander V. Chernikov } 1874b074b7bbSAlexander V. Chernikov 1875ac35ff17SAlexander V. Chernikov /* 1876ac35ff17SAlexander V. Chernikov * Finds table config based on either legacy index 1877ac35ff17SAlexander V. Chernikov * or name in ntlv. 1878ac35ff17SAlexander V. Chernikov * Note @ti structure contains unchecked data from userland. 1879ac35ff17SAlexander V. Chernikov * 1880ac35ff17SAlexander V. Chernikov * Returns pointer to table_config or NULL. 1881ac35ff17SAlexander V. Chernikov */ 1882b074b7bbSAlexander V. Chernikov static struct table_config * 1883b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti) 1884b074b7bbSAlexander V. Chernikov { 1885b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1886b074b7bbSAlexander V. Chernikov struct named_object *no; 1887ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1888ac35ff17SAlexander V. Chernikov uint32_t set; 1889b074b7bbSAlexander V. Chernikov 1890b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1891ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1892ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1893b074b7bbSAlexander V. Chernikov return (NULL); 1894ac35ff17SAlexander V. Chernikov name = ntlv->name; 1895ac35ff17SAlexander V. Chernikov set = ntlv->set; 1896b074b7bbSAlexander V. Chernikov } else { 1897b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1898b074b7bbSAlexander V. Chernikov name = bname; 1899ac35ff17SAlexander V. Chernikov set = 0; 1900b074b7bbSAlexander V. Chernikov } 1901b074b7bbSAlexander V. Chernikov 1902ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_name(ni, set, name); 1903b074b7bbSAlexander V. Chernikov 1904b074b7bbSAlexander V. Chernikov return ((struct table_config *)no); 1905b074b7bbSAlexander V. Chernikov } 1906b074b7bbSAlexander V. Chernikov 1907b074b7bbSAlexander V. Chernikov static struct table_config * 190868394ec8SAlexander V. Chernikov alloc_table_config(struct ip_fw_chain *ch, struct tid_info *ti, 1909db785d31SAlexander V. Chernikov struct table_algo *ta, char *aname, uint8_t vtype) 1910b074b7bbSAlexander V. Chernikov { 1911b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1912b074b7bbSAlexander V. Chernikov struct table_config *tc; 1913b074b7bbSAlexander V. Chernikov int error; 1914ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1915ac35ff17SAlexander V. Chernikov uint32_t set; 1916b074b7bbSAlexander V. Chernikov 1917b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1918ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1919ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1920b074b7bbSAlexander V. Chernikov return (NULL); 1921ac35ff17SAlexander V. Chernikov name = ntlv->name; 1922ac35ff17SAlexander V. Chernikov set = ntlv->set; 1923b074b7bbSAlexander V. Chernikov } else { 1924b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1925b074b7bbSAlexander V. Chernikov name = bname; 1926ac35ff17SAlexander V. Chernikov set = 0; 1927b074b7bbSAlexander V. Chernikov } 1928b074b7bbSAlexander V. Chernikov 1929b074b7bbSAlexander V. Chernikov tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO); 1930b074b7bbSAlexander V. Chernikov tc->no.name = tc->tablename; 1931b074b7bbSAlexander V. Chernikov tc->no.type = ti->type; 1932ac35ff17SAlexander V. Chernikov tc->no.set = set; 19339f7d47b0SAlexander V. Chernikov tc->ta = ta; 1934b074b7bbSAlexander V. Chernikov strlcpy(tc->tablename, name, sizeof(tc->tablename)); 1935ac35ff17SAlexander V. Chernikov /* Set default value type to u32 for compability reasons */ 1936db785d31SAlexander V. Chernikov if (vtype == 0) 1937ac35ff17SAlexander V. Chernikov tc->vtype = IPFW_VTYPE_U32; 1938db785d31SAlexander V. Chernikov else 1939db785d31SAlexander V. Chernikov tc->vtype = vtype; 1940b074b7bbSAlexander V. Chernikov 1941b074b7bbSAlexander V. Chernikov if (ti->tlvs == NULL) { 1942b074b7bbSAlexander V. Chernikov tc->no.compat = 1; 1943b074b7bbSAlexander V. Chernikov tc->no.uidx = ti->uidx; 1944b074b7bbSAlexander V. Chernikov } 1945b074b7bbSAlexander V. Chernikov 1946b074b7bbSAlexander V. Chernikov /* Preallocate data structures for new tables */ 194768394ec8SAlexander V. Chernikov error = ta->init(ch, &tc->astate, &tc->ti, aname); 1948b074b7bbSAlexander V. Chernikov if (error != 0) { 1949b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1950b074b7bbSAlexander V. Chernikov return (NULL); 1951b074b7bbSAlexander V. Chernikov } 1952b074b7bbSAlexander V. Chernikov 1953b074b7bbSAlexander V. Chernikov return (tc); 1954b074b7bbSAlexander V. Chernikov } 1955b074b7bbSAlexander V. Chernikov 1956b074b7bbSAlexander V. Chernikov static void 1957b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc) 1958b074b7bbSAlexander V. Chernikov { 1959b074b7bbSAlexander V. Chernikov 1960b074b7bbSAlexander V. Chernikov if (tc->linked == 0) 196168394ec8SAlexander V. Chernikov tc->ta->destroy(tc->astate, &tc->ti); 1962b074b7bbSAlexander V. Chernikov 1963b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1964b074b7bbSAlexander V. Chernikov } 1965b074b7bbSAlexander V. Chernikov 1966b074b7bbSAlexander V. Chernikov /* 1967b074b7bbSAlexander V. Chernikov * Links @tc to @chain table named instance. 1968b074b7bbSAlexander V. Chernikov * Sets appropriate type/states in @chain table info. 1969b074b7bbSAlexander V. Chernikov */ 1970b074b7bbSAlexander V. Chernikov static void 19719f7d47b0SAlexander V. Chernikov link_table(struct ip_fw_chain *ch, struct table_config *tc) 1972b074b7bbSAlexander V. Chernikov { 1973b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 19749f7d47b0SAlexander V. Chernikov struct table_info *ti; 1975b074b7bbSAlexander V. Chernikov uint16_t kidx; 1976b074b7bbSAlexander V. Chernikov 19779f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 19789f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1979b074b7bbSAlexander V. Chernikov 19809f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1981b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1982b074b7bbSAlexander V. Chernikov 1983b074b7bbSAlexander V. Chernikov ipfw_objhash_add(ni, &tc->no); 19849f7d47b0SAlexander V. Chernikov 19859f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 19869f7d47b0SAlexander V. Chernikov *ti = tc->ti; 1987b074b7bbSAlexander V. Chernikov 198868394ec8SAlexander V. Chernikov /* Notify algo on real @ti address */ 198968394ec8SAlexander V. Chernikov if (tc->ta->change_ti != NULL) 199068394ec8SAlexander V. Chernikov tc->ta->change_ti(tc->astate, ti); 199168394ec8SAlexander V. Chernikov 1992b074b7bbSAlexander V. Chernikov tc->linked = 1; 19939d099b4fSAlexander V. Chernikov tc->ta->refcnt++; 1994b074b7bbSAlexander V. Chernikov } 1995b074b7bbSAlexander V. Chernikov 1996b074b7bbSAlexander V. Chernikov /* 1997b074b7bbSAlexander V. Chernikov * Unlinks @tc from @chain table named instance. 1998b074b7bbSAlexander V. Chernikov * Zeroes states in @chain and stores them in @tc. 1999b074b7bbSAlexander V. Chernikov */ 2000b074b7bbSAlexander V. Chernikov static void 20019f7d47b0SAlexander V. Chernikov unlink_table(struct ip_fw_chain *ch, struct table_config *tc) 2002b074b7bbSAlexander V. Chernikov { 2003b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 20049f7d47b0SAlexander V. Chernikov struct table_info *ti; 2005b074b7bbSAlexander V. Chernikov uint16_t kidx; 2006b074b7bbSAlexander V. Chernikov 20079f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 20089f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 2009b074b7bbSAlexander V. Chernikov 20109f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 2011b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 2012b074b7bbSAlexander V. Chernikov 20139f7d47b0SAlexander V. Chernikov /* Clear state. @ti copy is already saved inside @tc */ 2014b074b7bbSAlexander V. Chernikov ipfw_objhash_del(ni, &tc->no); 20159f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 20169f7d47b0SAlexander V. Chernikov memset(ti, 0, sizeof(struct table_info)); 2017b074b7bbSAlexander V. Chernikov tc->linked = 0; 20189d099b4fSAlexander V. Chernikov tc->ta->refcnt--; 201968394ec8SAlexander V. Chernikov 202068394ec8SAlexander V. Chernikov /* Notify algo on real @ti address */ 202168394ec8SAlexander V. Chernikov if (tc->ta->change_ti != NULL) 202268394ec8SAlexander V. Chernikov tc->ta->change_ti(tc->astate, NULL); 2023b074b7bbSAlexander V. Chernikov } 2024b074b7bbSAlexander V. Chernikov 2025b074b7bbSAlexander V. Chernikov /* 2026b074b7bbSAlexander V. Chernikov * Finds named object by @uidx number. 2027b074b7bbSAlexander V. Chernikov * Refs found object, allocate new index for non-existing object. 20289490a627SAlexander V. Chernikov * Fills in @oib with userland/kernel indexes. 20299490a627SAlexander V. Chernikov * First free oidx pointer is saved back in @oib. 2030b074b7bbSAlexander V. Chernikov * 2031b074b7bbSAlexander V. Chernikov * Returns 0 on success. 2032b074b7bbSAlexander V. Chernikov */ 2033b074b7bbSAlexander V. Chernikov static int 20349490a627SAlexander V. Chernikov bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule, 20359490a627SAlexander V. Chernikov struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti) 2036b074b7bbSAlexander V. Chernikov { 2037b074b7bbSAlexander V. Chernikov struct table_config *tc; 20389490a627SAlexander V. Chernikov struct namedobj_instance *ni; 20399490a627SAlexander V. Chernikov struct named_object *no; 20409490a627SAlexander V. Chernikov int error, l, cmdlen; 20419490a627SAlexander V. Chernikov ipfw_insn *cmd; 20429490a627SAlexander V. Chernikov struct obj_idx *pidx, *p; 20439490a627SAlexander V. Chernikov 20449490a627SAlexander V. Chernikov pidx = *oib; 20459490a627SAlexander V. Chernikov l = rule->cmd_len; 20469490a627SAlexander V. Chernikov cmd = rule->cmd; 20479490a627SAlexander V. Chernikov cmdlen = 0; 20489490a627SAlexander V. Chernikov error = 0; 20499490a627SAlexander V. Chernikov 20509490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 20519490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 20529490a627SAlexander V. Chernikov 20539490a627SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 20549490a627SAlexander V. Chernikov cmdlen = F_LEN(cmd); 20559490a627SAlexander V. Chernikov 20569490a627SAlexander V. Chernikov if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0) 20579490a627SAlexander V. Chernikov continue; 2058b074b7bbSAlexander V. Chernikov 2059b074b7bbSAlexander V. Chernikov pidx->uidx = ti->uidx; 2060b074b7bbSAlexander V. Chernikov pidx->type = ti->type; 2061b074b7bbSAlexander V. Chernikov 20629490a627SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 20639490a627SAlexander V. Chernikov if (tc->no.type != ti->type) { 20649490a627SAlexander V. Chernikov /* Incompatible types */ 20659490a627SAlexander V. Chernikov error = EINVAL; 20669490a627SAlexander V. Chernikov break; 20679490a627SAlexander V. Chernikov } 20689f7d47b0SAlexander V. Chernikov 20699490a627SAlexander V. Chernikov /* Reference found table and save kidx */ 20709490a627SAlexander V. Chernikov tc->no.refcnt++; 20719490a627SAlexander V. Chernikov pidx->kidx = tc->no.kidx; 20729490a627SAlexander V. Chernikov pidx++; 20739490a627SAlexander V. Chernikov continue; 20749490a627SAlexander V. Chernikov } 20759490a627SAlexander V. Chernikov 20769490a627SAlexander V. Chernikov /* Table not found. Allocate new index and save for later */ 2077ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &pidx->kidx) != 0) { 2078ac35ff17SAlexander V. Chernikov printf("Unable to allocate table %s index in set %u." 2079b074b7bbSAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 2080ac35ff17SAlexander V. Chernikov "", ti->set); 20819490a627SAlexander V. Chernikov error = EBUSY; 20829490a627SAlexander V. Chernikov break; 2083b074b7bbSAlexander V. Chernikov } 2084b074b7bbSAlexander V. Chernikov 2085b074b7bbSAlexander V. Chernikov ci->new_tables++; 20869490a627SAlexander V. Chernikov pidx->new = 1; 20879490a627SAlexander V. Chernikov pidx++; 2088b074b7bbSAlexander V. Chernikov } 2089b074b7bbSAlexander V. Chernikov 20909490a627SAlexander V. Chernikov if (error != 0) { 20919490a627SAlexander V. Chernikov /* Unref everything we have already done */ 20929490a627SAlexander V. Chernikov for (p = *oib; p < pidx; p++) { 20939490a627SAlexander V. Chernikov if (p->new != 0) { 2094ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, p->kidx); 20959490a627SAlexander V. Chernikov continue; 20969490a627SAlexander V. Chernikov } 2097b074b7bbSAlexander V. Chernikov 20989490a627SAlexander V. Chernikov /* Find & unref by existing idx */ 2099ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, p->kidx); 21009490a627SAlexander V. Chernikov KASSERT(no != NULL, ("Ref'd table %d disappeared", 21019490a627SAlexander V. Chernikov p->kidx)); 2102b074b7bbSAlexander V. Chernikov 21039490a627SAlexander V. Chernikov no->refcnt--; 21049490a627SAlexander V. Chernikov } 21059490a627SAlexander V. Chernikov } 21069490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2107b074b7bbSAlexander V. Chernikov 21089490a627SAlexander V. Chernikov *oib = pidx; 21099490a627SAlexander V. Chernikov 21109490a627SAlexander V. Chernikov return (error); 2111b074b7bbSAlexander V. Chernikov } 2112b074b7bbSAlexander V. Chernikov 2113b074b7bbSAlexander V. Chernikov /* 2114b074b7bbSAlexander V. Chernikov * Compatibility function for old ipfw(8) binaries. 2115b074b7bbSAlexander V. Chernikov * Rewrites table kernel indices with userland ones. 2116b074b7bbSAlexander V. Chernikov * Works for \d+ talbes only (e.g. for tables, converted 2117b074b7bbSAlexander V. Chernikov * from old numbered system calls). 2118b074b7bbSAlexander V. Chernikov * 2119b074b7bbSAlexander V. Chernikov * Returns 0 on success. 2120b074b7bbSAlexander V. Chernikov * Raises error on any other tables. 2121b074b7bbSAlexander V. Chernikov */ 2122b074b7bbSAlexander V. Chernikov int 21237e767c79SAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw_rule0 *rule) 2124b074b7bbSAlexander V. Chernikov { 21251832a7b3SAlexander V. Chernikov int cmdlen, error, l; 2126b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 21271832a7b3SAlexander V. Chernikov uint16_t kidx, uidx; 2128b074b7bbSAlexander V. Chernikov uint8_t type; 2129b074b7bbSAlexander V. Chernikov struct named_object *no; 2130b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2131b074b7bbSAlexander V. Chernikov 2132b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 21331832a7b3SAlexander V. Chernikov error = 0; 2134b074b7bbSAlexander V. Chernikov 2135b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 2136b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 2137b074b7bbSAlexander V. Chernikov cmdlen = 0; 2138b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2139b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2140b074b7bbSAlexander V. Chernikov 2141b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2142b074b7bbSAlexander V. Chernikov continue; 2143b074b7bbSAlexander V. Chernikov 2144ac35ff17SAlexander V. Chernikov if ((no = ipfw_objhash_lookup_kidx(ni, kidx)) == NULL) 2145b074b7bbSAlexander V. Chernikov return (1); 2146b074b7bbSAlexander V. Chernikov 21471832a7b3SAlexander V. Chernikov uidx = no->uidx; 21481832a7b3SAlexander V. Chernikov if (no->compat == 0) { 2149b074b7bbSAlexander V. Chernikov 21501832a7b3SAlexander V. Chernikov /* 21511832a7b3SAlexander V. Chernikov * We are called via legacy opcode. 21521832a7b3SAlexander V. Chernikov * Save error and show table as fake number 21531832a7b3SAlexander V. Chernikov * not to make ipfw(8) hang. 21541832a7b3SAlexander V. Chernikov */ 21551832a7b3SAlexander V. Chernikov uidx = 65535; 21561832a7b3SAlexander V. Chernikov error = 2; 2157b074b7bbSAlexander V. Chernikov } 2158b074b7bbSAlexander V. Chernikov 21591832a7b3SAlexander V. Chernikov update_table_opcode(cmd, uidx); 21601832a7b3SAlexander V. Chernikov } 21611832a7b3SAlexander V. Chernikov 21621832a7b3SAlexander V. Chernikov return (error); 2163b074b7bbSAlexander V. Chernikov } 2164b074b7bbSAlexander V. Chernikov 2165563b5ab1SAlexander V. Chernikov /* 2166563b5ab1SAlexander V. Chernikov * Sets every table kidx in @bmask which is used in rule @rule. 2167563b5ab1SAlexander V. Chernikov * 2168563b5ab1SAlexander V. Chernikov * Returns number of newly-referenced tables. 2169563b5ab1SAlexander V. Chernikov */ 2170563b5ab1SAlexander V. Chernikov int 2171563b5ab1SAlexander V. Chernikov ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule, 2172563b5ab1SAlexander V. Chernikov uint32_t *bmask) 2173563b5ab1SAlexander V. Chernikov { 2174563b5ab1SAlexander V. Chernikov int cmdlen, l, count; 2175563b5ab1SAlexander V. Chernikov ipfw_insn *cmd; 2176563b5ab1SAlexander V. Chernikov uint16_t kidx; 2177563b5ab1SAlexander V. Chernikov uint8_t type; 2178563b5ab1SAlexander V. Chernikov 2179563b5ab1SAlexander V. Chernikov l = rule->cmd_len; 2180563b5ab1SAlexander V. Chernikov cmd = rule->cmd; 2181563b5ab1SAlexander V. Chernikov cmdlen = 0; 2182563b5ab1SAlexander V. Chernikov count = 0; 2183563b5ab1SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2184563b5ab1SAlexander V. Chernikov cmdlen = F_LEN(cmd); 2185563b5ab1SAlexander V. Chernikov 2186563b5ab1SAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2187563b5ab1SAlexander V. Chernikov continue; 2188563b5ab1SAlexander V. Chernikov 2189563b5ab1SAlexander V. Chernikov if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0) 2190563b5ab1SAlexander V. Chernikov count++; 2191563b5ab1SAlexander V. Chernikov 2192563b5ab1SAlexander V. Chernikov bmask[kidx / 32] |= 1 << (kidx % 32); 2193563b5ab1SAlexander V. Chernikov } 2194563b5ab1SAlexander V. Chernikov 2195563b5ab1SAlexander V. Chernikov return (count); 2196563b5ab1SAlexander V. Chernikov } 2197563b5ab1SAlexander V. Chernikov 2198563b5ab1SAlexander V. Chernikov 2199b074b7bbSAlexander V. Chernikov 2200b074b7bbSAlexander V. Chernikov /* 2201b074b7bbSAlexander V. Chernikov * Checks is opcode is referencing table of appropriate type. 2202b074b7bbSAlexander V. Chernikov * Adds reference count for found table if true. 2203b074b7bbSAlexander V. Chernikov * Rewrites user-supplied opcode values with kernel ones. 2204b074b7bbSAlexander V. Chernikov * 2205b074b7bbSAlexander V. Chernikov * Returns 0 on success and appropriate error code otherwise. 2206b074b7bbSAlexander V. Chernikov */ 2207b074b7bbSAlexander V. Chernikov int 2208b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, 2209b074b7bbSAlexander V. Chernikov struct rule_check_info *ci) 2210b074b7bbSAlexander V. Chernikov { 2211b074b7bbSAlexander V. Chernikov int cmdlen, error, ftype, l; 2212b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 2213b074b7bbSAlexander V. Chernikov uint16_t uidx; 2214b074b7bbSAlexander V. Chernikov uint8_t type; 2215b074b7bbSAlexander V. Chernikov struct table_config *tc; 22169f7d47b0SAlexander V. Chernikov struct table_algo *ta; 2217b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2218b074b7bbSAlexander V. Chernikov struct named_object *no, *no_n, *no_tmp; 22199490a627SAlexander V. Chernikov struct obj_idx *p, *pidx_first, *pidx_last; 2220b074b7bbSAlexander V. Chernikov struct namedobjects_head nh; 2221b074b7bbSAlexander V. Chernikov struct tid_info ti; 2222b074b7bbSAlexander V. Chernikov 2223b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 2224b074b7bbSAlexander V. Chernikov 22259490a627SAlexander V. Chernikov /* Prepare queue to store configs */ 22269490a627SAlexander V. Chernikov TAILQ_INIT(&nh); 22279490a627SAlexander V. Chernikov 2228b074b7bbSAlexander V. Chernikov /* 2229b074b7bbSAlexander V. Chernikov * Prepare an array for storing opcode indices. 2230b074b7bbSAlexander V. Chernikov * Use stack allocation by default. 2231b074b7bbSAlexander V. Chernikov */ 2232b074b7bbSAlexander V. Chernikov if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 2233b074b7bbSAlexander V. Chernikov /* Stack */ 22349490a627SAlexander V. Chernikov pidx_first = ci->obuf; 2235b074b7bbSAlexander V. Chernikov } else 22369490a627SAlexander V. Chernikov pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx), 2237b074b7bbSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 2238b074b7bbSAlexander V. Chernikov 22399490a627SAlexander V. Chernikov pidx_last = pidx_first; 2240b074b7bbSAlexander V. Chernikov error = 0; 2241b074b7bbSAlexander V. Chernikov 2242b074b7bbSAlexander V. Chernikov type = 0; 2243b074b7bbSAlexander V. Chernikov ftype = 0; 2244b074b7bbSAlexander V. Chernikov 2245b074b7bbSAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 22461832a7b3SAlexander V. Chernikov 22471832a7b3SAlexander V. Chernikov /* 22481832a7b3SAlexander V. Chernikov * Use default set for looking up tables (old way) or 22491832a7b3SAlexander V. Chernikov * use set rule is assigned to (new way). 22501832a7b3SAlexander V. Chernikov */ 22511832a7b3SAlexander V. Chernikov ti.set = (V_fw_tables_sets != 0) ? ci->krule->set : 0; 22526c2997ffSAlexander V. Chernikov if (ci->ctlv != NULL) { 22536c2997ffSAlexander V. Chernikov ti.tlvs = (void *)(ci->ctlv + 1); 22546c2997ffSAlexander V. Chernikov ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv); 22556c2997ffSAlexander V. Chernikov } 2256b074b7bbSAlexander V. Chernikov 2257b074b7bbSAlexander V. Chernikov /* 22589490a627SAlexander V. Chernikov * Stage 1: reference existing tables, determine number 22599490a627SAlexander V. Chernikov * of tables we need to allocate and allocate indexes for each. 2260b074b7bbSAlexander V. Chernikov */ 22619490a627SAlexander V. Chernikov error = bind_table_rule(chain, ci->krule, ci, &pidx_last, &ti); 2262b074b7bbSAlexander V. Chernikov 2263b074b7bbSAlexander V. Chernikov if (error != 0) { 22649490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 22659490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 2266b074b7bbSAlexander V. Chernikov 2267b074b7bbSAlexander V. Chernikov return (error); 2268b074b7bbSAlexander V. Chernikov } 2269b074b7bbSAlexander V. Chernikov 2270b074b7bbSAlexander V. Chernikov /* 2271b074b7bbSAlexander V. Chernikov * Stage 2: allocate table configs for every non-existent table 2272b074b7bbSAlexander V. Chernikov */ 2273b074b7bbSAlexander V. Chernikov 22749f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 22759490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 2276b074b7bbSAlexander V. Chernikov if (p->new == 0) 2277b074b7bbSAlexander V. Chernikov continue; 2278b074b7bbSAlexander V. Chernikov 2279b074b7bbSAlexander V. Chernikov ti.uidx = p->uidx; 2280b074b7bbSAlexander V. Chernikov ti.type = p->type; 22819f7d47b0SAlexander V. Chernikov ti.atype = 0; 2282b074b7bbSAlexander V. Chernikov 22839490a627SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti, NULL); 22849f7d47b0SAlexander V. Chernikov if (ta == NULL) { 22859f7d47b0SAlexander V. Chernikov error = ENOTSUP; 22869f7d47b0SAlexander V. Chernikov goto free; 22879f7d47b0SAlexander V. Chernikov } 228868394ec8SAlexander V. Chernikov tc = alloc_table_config(chain, &ti, ta, NULL, 228968394ec8SAlexander V. Chernikov IPFW_VTYPE_U32); 2290b074b7bbSAlexander V. Chernikov 2291b074b7bbSAlexander V. Chernikov if (tc == NULL) { 2292b074b7bbSAlexander V. Chernikov error = ENOMEM; 2293b074b7bbSAlexander V. Chernikov goto free; 2294b074b7bbSAlexander V. Chernikov } 2295b074b7bbSAlexander V. Chernikov 2296b074b7bbSAlexander V. Chernikov tc->no.kidx = p->kidx; 2297b074b7bbSAlexander V. Chernikov tc->no.refcnt = 1; 2298b074b7bbSAlexander V. Chernikov 2299b074b7bbSAlexander V. Chernikov /* Add to list */ 2300b074b7bbSAlexander V. Chernikov TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next); 2301b074b7bbSAlexander V. Chernikov } 2302b074b7bbSAlexander V. Chernikov 2303b074b7bbSAlexander V. Chernikov /* 2304b074b7bbSAlexander V. Chernikov * Stage 2.1: Check if we're going to create 2 tables 2305b074b7bbSAlexander V. Chernikov * with the same name, but different table types. 2306b074b7bbSAlexander V. Chernikov */ 2307b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no, &nh, nn_next) { 2308b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no_tmp, &nh, nn_next) { 23099490a627SAlexander V. Chernikov if (ipfw_objhash_same_name(ni, no, no_tmp) == 0) 2310b074b7bbSAlexander V. Chernikov continue; 2311b074b7bbSAlexander V. Chernikov if (no->type != no_tmp->type) { 2312b074b7bbSAlexander V. Chernikov error = EINVAL; 2313b074b7bbSAlexander V. Chernikov goto free; 2314b074b7bbSAlexander V. Chernikov } 2315b074b7bbSAlexander V. Chernikov } 2316b074b7bbSAlexander V. Chernikov } 23179f7d47b0SAlexander V. Chernikov } 2318b074b7bbSAlexander V. Chernikov 23199f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 23209f7d47b0SAlexander V. Chernikov 23219f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 2322b074b7bbSAlexander V. Chernikov /* 2323b074b7bbSAlexander V. Chernikov * Stage 3: link & reference new table configs 2324b074b7bbSAlexander V. Chernikov */ 2325b074b7bbSAlexander V. Chernikov 2326b074b7bbSAlexander V. Chernikov 2327b074b7bbSAlexander V. Chernikov /* 2328b074b7bbSAlexander V. Chernikov * Step 3.1: Check if some tables we need to create have been 2329b074b7bbSAlexander V. Chernikov * already created with different table type. 2330b074b7bbSAlexander V. Chernikov */ 2331b074b7bbSAlexander V. Chernikov 2332b074b7bbSAlexander V. Chernikov error = 0; 2333b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2334b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 2335b074b7bbSAlexander V. Chernikov if (no_n == NULL) 2336b074b7bbSAlexander V. Chernikov continue; 2337b074b7bbSAlexander V. Chernikov 2338b074b7bbSAlexander V. Chernikov if (no_n->type != no->type) { 2339b074b7bbSAlexander V. Chernikov error = EINVAL; 2340b074b7bbSAlexander V. Chernikov break; 2341b074b7bbSAlexander V. Chernikov } 2342b074b7bbSAlexander V. Chernikov 2343b074b7bbSAlexander V. Chernikov } 2344b074b7bbSAlexander V. Chernikov 2345b074b7bbSAlexander V. Chernikov if (error != 0) { 2346b074b7bbSAlexander V. Chernikov /* 2347b074b7bbSAlexander V. Chernikov * Someone has allocated table with different table type. 2348b074b7bbSAlexander V. Chernikov * We have to rollback everything. 2349b074b7bbSAlexander V. Chernikov */ 2350b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 2351b074b7bbSAlexander V. Chernikov goto free; 2352b074b7bbSAlexander V. Chernikov } 2353b074b7bbSAlexander V. Chernikov 2354b074b7bbSAlexander V. Chernikov /* 23559f7d47b0SAlexander V. Chernikov * Attach new tables. 23569f7d47b0SAlexander V. Chernikov * We need to set table pointers for each new table, 2357b074b7bbSAlexander V. Chernikov * so we have to acquire main WLOCK. 2358b074b7bbSAlexander V. Chernikov */ 2359b074b7bbSAlexander V. Chernikov IPFW_WLOCK(chain); 2360b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2361b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 2362b074b7bbSAlexander V. Chernikov 23639490a627SAlexander V. Chernikov if (no_n == NULL) { 23649490a627SAlexander V. Chernikov /* New table. Attach to runtime hash */ 23659490a627SAlexander V. Chernikov TAILQ_REMOVE(&nh, no, nn_next); 23669490a627SAlexander V. Chernikov link_table(chain, (struct table_config *)no); 2367b074b7bbSAlexander V. Chernikov continue; 2368b074b7bbSAlexander V. Chernikov } 2369b074b7bbSAlexander V. Chernikov 23709490a627SAlexander V. Chernikov /* 23719490a627SAlexander V. Chernikov * Newly-allocated table with the same type. 23729490a627SAlexander V. Chernikov * Reference it and update out @pidx array 23739490a627SAlexander V. Chernikov * rewrite info. 23749490a627SAlexander V. Chernikov */ 23759490a627SAlexander V. Chernikov no_n->refcnt++; 23769490a627SAlexander V. Chernikov /* Keep oib array in sync: update kidx */ 23779490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 23789490a627SAlexander V. Chernikov if (p->kidx != no->kidx) 23799490a627SAlexander V. Chernikov continue; 23809490a627SAlexander V. Chernikov /* Update kidx */ 23819490a627SAlexander V. Chernikov p->kidx = no_n->kidx; 23829490a627SAlexander V. Chernikov break; 23839490a627SAlexander V. Chernikov } 2384b074b7bbSAlexander V. Chernikov } 2385b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(chain); 23869f7d47b0SAlexander V. Chernikov } 2387b074b7bbSAlexander V. Chernikov 2388b074b7bbSAlexander V. Chernikov /* Perform rule rewrite */ 2389b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 2390b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 2391b074b7bbSAlexander V. Chernikov cmdlen = 0; 23929490a627SAlexander V. Chernikov p = pidx_first; 2393b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2394b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2395b074b7bbSAlexander V. Chernikov 2396b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &uidx, &type) != 0) 2397b074b7bbSAlexander V. Chernikov continue; 23989490a627SAlexander V. Chernikov update_table_opcode(cmd, p->kidx); 23999490a627SAlexander V. Chernikov p++; 2400b074b7bbSAlexander V. Chernikov } 2401b074b7bbSAlexander V. Chernikov 2402b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 2403b074b7bbSAlexander V. Chernikov 2404b074b7bbSAlexander V. Chernikov error = 0; 2405b074b7bbSAlexander V. Chernikov 2406b074b7bbSAlexander V. Chernikov /* 2407b074b7bbSAlexander V. Chernikov * Stage 4: free resources 2408b074b7bbSAlexander V. Chernikov */ 2409b074b7bbSAlexander V. Chernikov free: 24109490a627SAlexander V. Chernikov if (!TAILQ_EMPTY(&nh)) { 24119490a627SAlexander V. Chernikov /* Free indexes first */ 24129490a627SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 24139490a627SAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2414ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, no->kidx); 24159490a627SAlexander V. Chernikov } 24169490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 24179490a627SAlexander V. Chernikov /* Free configs */ 2418b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) 2419b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 24209490a627SAlexander V. Chernikov } 2421b074b7bbSAlexander V. Chernikov 24229490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 24239490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 2424b074b7bbSAlexander V. Chernikov 2425b074b7bbSAlexander V. Chernikov return (error); 2426b074b7bbSAlexander V. Chernikov } 2427b074b7bbSAlexander V. Chernikov 2428b074b7bbSAlexander V. Chernikov /* 2429b074b7bbSAlexander V. Chernikov * Remove references from every table used in @rule. 2430b074b7bbSAlexander V. Chernikov */ 2431b074b7bbSAlexander V. Chernikov void 2432b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule) 2433b074b7bbSAlexander V. Chernikov { 2434b074b7bbSAlexander V. Chernikov int cmdlen, l; 2435b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 2436b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2437b074b7bbSAlexander V. Chernikov struct named_object *no; 2438b074b7bbSAlexander V. Chernikov uint16_t kidx; 2439b074b7bbSAlexander V. Chernikov uint8_t type; 2440b074b7bbSAlexander V. Chernikov 2441b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 2442b074b7bbSAlexander V. Chernikov 2443b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 2444b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 2445b074b7bbSAlexander V. Chernikov cmdlen = 0; 2446b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2447b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2448b074b7bbSAlexander V. Chernikov 2449b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2450b074b7bbSAlexander V. Chernikov continue; 2451b074b7bbSAlexander V. Chernikov 2452ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 2453b074b7bbSAlexander V. Chernikov 2454b074b7bbSAlexander V. Chernikov KASSERT(no != NULL, ("table id %d not found", kidx)); 2455b074b7bbSAlexander V. Chernikov KASSERT(no->type == type, ("wrong type %d (%d) for table id %d", 2456b074b7bbSAlexander V. Chernikov no->type, type, kidx)); 2457b074b7bbSAlexander V. Chernikov KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 2458b074b7bbSAlexander V. Chernikov kidx, no->refcnt)); 2459b074b7bbSAlexander V. Chernikov 2460b074b7bbSAlexander V. Chernikov no->refcnt--; 2461b074b7bbSAlexander V. Chernikov } 2462b074b7bbSAlexander V. Chernikov } 2463b074b7bbSAlexander V. Chernikov 2464b074b7bbSAlexander V. Chernikov 2465b074b7bbSAlexander V. Chernikov /* 2466b074b7bbSAlexander V. Chernikov * Removes table bindings for every rule in rule chain @head. 2467b074b7bbSAlexander V. Chernikov */ 2468b074b7bbSAlexander V. Chernikov void 2469b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head) 2470b074b7bbSAlexander V. Chernikov { 2471b074b7bbSAlexander V. Chernikov struct ip_fw *rule; 2472b074b7bbSAlexander V. Chernikov 2473b074b7bbSAlexander V. Chernikov while ((rule = head) != NULL) { 2474b074b7bbSAlexander V. Chernikov head = head->x_next; 2475b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(chain, rule); 2476b074b7bbSAlexander V. Chernikov } 2477b074b7bbSAlexander V. Chernikov } 2478b074b7bbSAlexander V. Chernikov 2479b074b7bbSAlexander V. Chernikov 24803b3a8eb9SGleb Smirnoff /* end of file */ 2481