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 */ 809f7d47b0SAlexander V. Chernikov uint16_t spare0; 81b074b7bbSAlexander V. Chernikov uint32_t count; /* Number of records */ 82b074b7bbSAlexander V. Chernikov char tablename[64]; /* table name */ 839f7d47b0SAlexander V. Chernikov struct table_algo *ta; /* Callbacks for given algo */ 849f7d47b0SAlexander V. Chernikov void *astate; /* algorithm state */ 859f7d47b0SAlexander V. Chernikov struct table_info ti; /* data to put to table_info */ 86b074b7bbSAlexander V. Chernikov }; 87b074b7bbSAlexander V. Chernikov #define TABLE_SET(set) ((V_fw_tables_sets != 0) ? set : 0) 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); 97b074b7bbSAlexander V. Chernikov static struct table_config *alloc_table_config(struct namedobj_instance *ni, 989490a627SAlexander V. Chernikov struct tid_info *ti, struct table_algo *ta, char *adata); 99b074b7bbSAlexander V. Chernikov static void free_table_config(struct namedobj_instance *ni, 100b074b7bbSAlexander V. Chernikov struct table_config *tc); 101b074b7bbSAlexander V. Chernikov static void link_table(struct ip_fw_chain *chain, struct table_config *tc); 102b074b7bbSAlexander V. Chernikov static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc); 103b074b7bbSAlexander V. Chernikov static void free_table_state(void **state, void **xstate, uint8_t type); 1042d99a349SAlexander V. Chernikov static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 1052d99a349SAlexander V. Chernikov struct sockopt_data *sd); 106ac35ff17SAlexander V. Chernikov static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 107ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i); 108f1220db8SAlexander V. Chernikov static int dump_table_xentry(void *e, void *arg); 109b074b7bbSAlexander V. Chernikov 1102d99a349SAlexander V. Chernikov static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd); 1112d99a349SAlexander V. Chernikov static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd); 112ac35ff17SAlexander V. Chernikov static int ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 113ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 114ac35ff17SAlexander V. Chernikov static int ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 115ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 116ac35ff17SAlexander V. Chernikov 117ac35ff17SAlexander V. Chernikov static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti); 118d3a4f924SAlexander V. Chernikov 1199f7d47b0SAlexander V. Chernikov static struct table_algo *find_table_algo(struct tables_config *tableconf, 1209490a627SAlexander V. Chernikov struct tid_info *ti, char *name); 121b074b7bbSAlexander V. Chernikov 122b074b7bbSAlexander V. Chernikov #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) 123b074b7bbSAlexander V. Chernikov #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) 1249f7d47b0SAlexander V. Chernikov #define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) 125b074b7bbSAlexander V. Chernikov 126b074b7bbSAlexander V. Chernikov 1273b3a8eb9SGleb Smirnoff 1283b3a8eb9SGleb Smirnoff int 1291832a7b3SAlexander V. Chernikov add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 130b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 1313b3a8eb9SGleb Smirnoff { 132b074b7bbSAlexander V. Chernikov struct table_config *tc, *tc_new; 1339f7d47b0SAlexander V. Chernikov struct table_algo *ta; 134b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 135b074b7bbSAlexander V. Chernikov uint16_t kidx; 1369f7d47b0SAlexander V. Chernikov int error; 1379f7d47b0SAlexander V. Chernikov char ta_buf[128]; 1383b3a8eb9SGleb Smirnoff 1399f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1409f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1419f7d47b0SAlexander V. Chernikov 1429f7d47b0SAlexander V. Chernikov /* 1439f7d47b0SAlexander V. Chernikov * Find and reference existing table. 1449f7d47b0SAlexander V. Chernikov */ 1459f7d47b0SAlexander V. Chernikov ta = NULL; 1469f7d47b0SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1479f7d47b0SAlexander V. Chernikov /* check table type */ 1489f7d47b0SAlexander V. Chernikov if (tc->no.type != ti->type) { 1499f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1503b3a8eb9SGleb Smirnoff return (EINVAL); 1513b3a8eb9SGleb Smirnoff } 1523b3a8eb9SGleb Smirnoff 1539f7d47b0SAlexander V. Chernikov /* Reference and unlock */ 1549f7d47b0SAlexander V. Chernikov tc->no.refcnt++; 1559f7d47b0SAlexander V. Chernikov ta = tc->ta; 1569f7d47b0SAlexander V. Chernikov } 1579f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1583b3a8eb9SGleb Smirnoff 1599f7d47b0SAlexander V. Chernikov tc_new = NULL; 160ac35ff17SAlexander V. Chernikov if (tc == NULL) { 1619f7d47b0SAlexander V. Chernikov /* Table not found. We have to create new one */ 1629490a627SAlexander V. Chernikov if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, NULL)) == NULL) 1639f7d47b0SAlexander V. Chernikov return (ENOTSUP); 1643b3a8eb9SGleb Smirnoff 1659490a627SAlexander V. Chernikov tc_new = alloc_table_config(ni, ti, ta, NULL); 1669f7d47b0SAlexander V. Chernikov if (tc_new == NULL) 1679f7d47b0SAlexander V. Chernikov return (ENOMEM); 1689f7d47b0SAlexander V. Chernikov } 1693b3a8eb9SGleb Smirnoff 1709f7d47b0SAlexander V. Chernikov /* Prepare record (allocate memory) */ 1719f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 1729f7d47b0SAlexander V. Chernikov error = ta->prepare_add(tei, &ta_buf); 1739f7d47b0SAlexander V. Chernikov if (error != 0) { 1749f7d47b0SAlexander V. Chernikov if (tc_new != NULL) 1759f7d47b0SAlexander V. Chernikov free_table_config(ni, tc_new); 1769f7d47b0SAlexander V. Chernikov return (error); 1773b3a8eb9SGleb Smirnoff } 1783b3a8eb9SGleb Smirnoff 179b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1803b3a8eb9SGleb Smirnoff 181b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1823b3a8eb9SGleb Smirnoff 1839f7d47b0SAlexander V. Chernikov if (tc == NULL) { 184ac35ff17SAlexander V. Chernikov /* Check if another table has been allocated by other thread */ 185b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1869f7d47b0SAlexander V. Chernikov 1879f7d47b0SAlexander V. Chernikov /* 1889f7d47b0SAlexander V. Chernikov * Check if algoritm is the same since we've 1899f7d47b0SAlexander V. Chernikov * already allocated state using @ta algoritm 1909f7d47b0SAlexander V. Chernikov * callbacks. 1919f7d47b0SAlexander V. Chernikov */ 1929f7d47b0SAlexander V. Chernikov if (tc->ta != ta) { 193b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 194ac35ff17SAlexander V. Chernikov error = EINVAL; 195ac35ff17SAlexander V. Chernikov goto done; 1963b3a8eb9SGleb Smirnoff } 1973b3a8eb9SGleb Smirnoff } else { 198ac35ff17SAlexander V. Chernikov /* Table still does not exists */ 199b074b7bbSAlexander V. Chernikov 200b074b7bbSAlexander V. Chernikov /* Allocate table index. */ 201ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) { 202b074b7bbSAlexander V. Chernikov /* Index full. */ 203b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 204ac35ff17SAlexander V. Chernikov printf("Unable to allocate index for table %s" 205ac35ff17SAlexander V. Chernikov "in set %u. Consider increasing " 206b074b7bbSAlexander V. Chernikov "net.inet.ip.fw.tables_max", 207ac35ff17SAlexander V. Chernikov tc_new->no.name, ti->set); 208ac35ff17SAlexander V. Chernikov error = EBUSY; 209ac35ff17SAlexander V. Chernikov goto done; 2103b3a8eb9SGleb Smirnoff } 211ac35ff17SAlexander V. Chernikov 212ac35ff17SAlexander V. Chernikov /* Set tc_new to zero not to free it afterwards. */ 213ac35ff17SAlexander V. Chernikov tc = tc_new; 214ac35ff17SAlexander V. Chernikov tc_new = NULL; 215b074b7bbSAlexander V. Chernikov /* Save kidx */ 216b074b7bbSAlexander V. Chernikov tc->no.kidx = kidx; 217b074b7bbSAlexander V. Chernikov } 218b074b7bbSAlexander V. Chernikov } else { 2199f7d47b0SAlexander V. Chernikov /* Drop reference we've used in first search */ 2209f7d47b0SAlexander V. Chernikov tc->no.refcnt--; 221b074b7bbSAlexander V. Chernikov } 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; 2269f7d47b0SAlexander V. Chernikov 227b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 228b074b7bbSAlexander V. Chernikov 229ac35ff17SAlexander V. Chernikov if (tc->linked == 0) 230b074b7bbSAlexander V. Chernikov link_table(ch, tc); 231b074b7bbSAlexander V. Chernikov 2329f7d47b0SAlexander V. Chernikov error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); 2333b3a8eb9SGleb Smirnoff 2343b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2359f7d47b0SAlexander V. Chernikov 236ac35ff17SAlexander V. Chernikov /* Update number of records. */ 237ac35ff17SAlexander V. Chernikov if (error == 0 && (tei->flags & TEI_FLAGS_UPDATED) == 0) 2389f7d47b0SAlexander V. Chernikov tc->count++; 2399f7d47b0SAlexander V. Chernikov 240b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 241b074b7bbSAlexander V. Chernikov 242ac35ff17SAlexander V. Chernikov done: 243b074b7bbSAlexander V. Chernikov if (tc_new != NULL) 244ac35ff17SAlexander V. Chernikov free_table_config(ni, tc_new); 245ac35ff17SAlexander V. Chernikov /* Run cleaning callback anyway */ 2469f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 247b074b7bbSAlexander V. Chernikov 2489f7d47b0SAlexander V. Chernikov return (error); 2493b3a8eb9SGleb Smirnoff } 2503b3a8eb9SGleb Smirnoff 2513b3a8eb9SGleb Smirnoff int 2521832a7b3SAlexander V. Chernikov del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 253b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 2543b3a8eb9SGleb Smirnoff { 255b074b7bbSAlexander V. Chernikov struct table_config *tc; 2569f7d47b0SAlexander V. Chernikov struct table_algo *ta; 257b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 258b074b7bbSAlexander V. Chernikov uint16_t kidx; 2599f7d47b0SAlexander V. Chernikov int error; 2609f7d47b0SAlexander V. Chernikov char ta_buf[128]; 2613b3a8eb9SGleb Smirnoff 2629f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 263b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 264b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 2659f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2663b3a8eb9SGleb Smirnoff return (ESRCH); 2673b3a8eb9SGleb Smirnoff } 2683b3a8eb9SGleb Smirnoff 269b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 2709f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2713b3a8eb9SGleb Smirnoff return (EINVAL); 2723b3a8eb9SGleb Smirnoff } 2739f7d47b0SAlexander V. Chernikov 2749f7d47b0SAlexander V. Chernikov ta = tc->ta; 2759f7d47b0SAlexander V. Chernikov 2769f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 2779f7d47b0SAlexander V. Chernikov if ((error = ta->prepare_del(tei, &ta_buf)) != 0) { 2789f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2799f7d47b0SAlexander V. Chernikov return (error); 2809f7d47b0SAlexander V. Chernikov } 2819f7d47b0SAlexander V. Chernikov 282b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 283b074b7bbSAlexander V. Chernikov 284b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 2859f7d47b0SAlexander V. Chernikov error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); 2863b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2873b3a8eb9SGleb Smirnoff 2889f7d47b0SAlexander V. Chernikov if (error == 0) 2899f7d47b0SAlexander V. Chernikov tc->count--; 290b074b7bbSAlexander V. Chernikov 2919f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2923b3a8eb9SGleb Smirnoff 2939f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 294ac35ff17SAlexander V. Chernikov 295ac35ff17SAlexander V. Chernikov return (error); 296ac35ff17SAlexander V. Chernikov } 297ac35ff17SAlexander V. Chernikov 298ac35ff17SAlexander V. Chernikov int 299ac35ff17SAlexander V. Chernikov ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 300ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 301ac35ff17SAlexander V. Chernikov { 302ac35ff17SAlexander V. Chernikov int error; 303ac35ff17SAlexander V. Chernikov 304ac35ff17SAlexander V. Chernikov switch (op3->version) { 305ac35ff17SAlexander V. Chernikov case 0: 306ac35ff17SAlexander V. Chernikov error = ipfw_modify_table_v0(ch, op3, sd); 307ac35ff17SAlexander V. Chernikov break; 308ac35ff17SAlexander V. Chernikov case 1: 309ac35ff17SAlexander V. Chernikov error = ipfw_modify_table_v1(ch, op3, sd); 310ac35ff17SAlexander V. Chernikov break; 311ac35ff17SAlexander V. Chernikov default: 312ac35ff17SAlexander V. Chernikov error = ENOTSUP; 313ac35ff17SAlexander V. Chernikov } 314ac35ff17SAlexander V. Chernikov 315ac35ff17SAlexander V. Chernikov return (error); 316ac35ff17SAlexander V. Chernikov } 317ac35ff17SAlexander V. Chernikov 318ac35ff17SAlexander V. Chernikov /* 319ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 320ac35ff17SAlexander V. Chernikov * Data layout (v0): 321ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ipfw_table_xentry ] 322ac35ff17SAlexander V. Chernikov * 323ac35ff17SAlexander V. Chernikov * Returns 0 on success 324ac35ff17SAlexander V. Chernikov */ 325ac35ff17SAlexander V. Chernikov static int 326ac35ff17SAlexander V. Chernikov ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 327ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 328ac35ff17SAlexander V. Chernikov { 329ac35ff17SAlexander V. Chernikov ipfw_table_xentry *xent; 330ac35ff17SAlexander V. Chernikov struct tentry_info tei; 331ac35ff17SAlexander V. Chernikov struct tid_info ti; 332ac35ff17SAlexander V. Chernikov int error, hdrlen, read; 333ac35ff17SAlexander V. Chernikov 334ac35ff17SAlexander V. Chernikov hdrlen = offsetof(ipfw_table_xentry, k); 335ac35ff17SAlexander V. Chernikov 336ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 337ac35ff17SAlexander V. Chernikov if (sd->valsize < (sizeof(*op3) + hdrlen)) 338ac35ff17SAlexander V. Chernikov return (EINVAL); 339ac35ff17SAlexander V. Chernikov 340ac35ff17SAlexander V. Chernikov read = sizeof(ip_fw3_opheader); 341ac35ff17SAlexander V. Chernikov 342ac35ff17SAlexander V. Chernikov /* Check if xentry len field is valid */ 343ac35ff17SAlexander V. Chernikov xent = (ipfw_table_xentry *)(op3 + 1); 344ac35ff17SAlexander V. Chernikov if (xent->len < hdrlen || xent->len + read > sd->valsize) 345ac35ff17SAlexander V. Chernikov return (EINVAL); 346ac35ff17SAlexander V. Chernikov 347ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 348ac35ff17SAlexander V. Chernikov tei.paddr = &xent->k; 349ac35ff17SAlexander V. Chernikov tei.masklen = xent->masklen; 350ac35ff17SAlexander V. Chernikov tei.value = xent->value; 351ac35ff17SAlexander V. Chernikov /* Old requests compability */ 352ac35ff17SAlexander V. Chernikov if (xent->type == IPFW_TABLE_CIDR) { 353ac35ff17SAlexander V. Chernikov if (xent->len - hdrlen == sizeof(in_addr_t)) 354ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET; 355ac35ff17SAlexander V. Chernikov else 356ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET6; 357ac35ff17SAlexander V. Chernikov } 358ac35ff17SAlexander V. Chernikov 359ac35ff17SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 360ac35ff17SAlexander V. Chernikov ti.uidx = xent->tbl; 361ac35ff17SAlexander V. Chernikov ti.type = xent->type; 362ac35ff17SAlexander V. Chernikov 363ac35ff17SAlexander V. Chernikov error = (op3->opcode == IP_FW_TABLE_XADD) ? 3641832a7b3SAlexander V. Chernikov add_table_entry(ch, &ti, &tei) : 3651832a7b3SAlexander V. Chernikov del_table_entry(ch, &ti, &tei); 366ac35ff17SAlexander V. Chernikov 367ac35ff17SAlexander V. Chernikov return (error); 368ac35ff17SAlexander V. Chernikov } 369ac35ff17SAlexander V. Chernikov 370ac35ff17SAlexander V. Chernikov /* 371ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 372ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 373ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_obj_tentry ] 374ac35ff17SAlexander V. Chernikov * 375ac35ff17SAlexander V. Chernikov * Returns 0 on success 376ac35ff17SAlexander V. Chernikov */ 377ac35ff17SAlexander V. Chernikov static int 378ac35ff17SAlexander V. Chernikov ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 379ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 380ac35ff17SAlexander V. Chernikov { 381ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent; 382ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 383ac35ff17SAlexander V. Chernikov struct tentry_info tei; 384ac35ff17SAlexander V. Chernikov struct tid_info ti; 385ac35ff17SAlexander V. Chernikov int error, read; 386ac35ff17SAlexander V. Chernikov 387ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 388ac35ff17SAlexander V. Chernikov if (sd->valsize < (sizeof(*oh) + sizeof(*tent))) 389ac35ff17SAlexander V. Chernikov return (EINVAL); 390ac35ff17SAlexander V. Chernikov 391ac35ff17SAlexander V. Chernikov /* Check if passed data is too long */ 392ac35ff17SAlexander V. Chernikov if (sd->valsize != sd->kavail) 393ac35ff17SAlexander V. Chernikov return (EINVAL); 394ac35ff17SAlexander V. Chernikov 395ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)sd->kbuf; 396ac35ff17SAlexander V. Chernikov 397ac35ff17SAlexander V. Chernikov /* Basic length checks for TLVs */ 398ac35ff17SAlexander V. Chernikov if (oh->ntlv.head.length != sizeof(oh->ntlv)) 399ac35ff17SAlexander V. Chernikov return (EINVAL); 400ac35ff17SAlexander V. Chernikov 401ac35ff17SAlexander V. Chernikov read = sizeof(*oh); 402ac35ff17SAlexander V. Chernikov 403ac35ff17SAlexander V. Chernikov /* Assume tentry may grow to support larger keys */ 404ac35ff17SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 405ac35ff17SAlexander V. Chernikov if (tent->head.length < sizeof(*tent) || 406ac35ff17SAlexander V. Chernikov tent->head.length + read > sd->valsize) 407ac35ff17SAlexander V. Chernikov return (EINVAL); 408ac35ff17SAlexander V. Chernikov 409ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 410ac35ff17SAlexander V. Chernikov tei.paddr = &tent->k; 411ac35ff17SAlexander V. Chernikov tei.subtype = tent->subtype; 412ac35ff17SAlexander V. Chernikov tei.masklen = tent->masklen; 413ac35ff17SAlexander V. Chernikov if (tent->flags & IPFW_TF_UPDATE) 414ac35ff17SAlexander V. Chernikov tei.flags |= TEI_FLAGS_UPDATE; 415ac35ff17SAlexander V. Chernikov tei.value = tent->value; 416ac35ff17SAlexander V. Chernikov 417ac35ff17SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 418ac35ff17SAlexander V. Chernikov ti.uidx = tent->idx; 419ac35ff17SAlexander V. Chernikov ti.type = oh->ntlv.type; 420ac35ff17SAlexander V. Chernikov ti.tlvs = &oh->ntlv; 421ac35ff17SAlexander V. Chernikov ti.tlen = oh->ntlv.head.length; 422ac35ff17SAlexander V. Chernikov 423ac35ff17SAlexander V. Chernikov error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ? 4241832a7b3SAlexander V. Chernikov add_table_entry(ch, &ti, &tei) : 4251832a7b3SAlexander V. Chernikov del_table_entry(ch, &ti, &tei); 426ac35ff17SAlexander V. Chernikov 427ac35ff17SAlexander V. Chernikov return (error); 428ac35ff17SAlexander V. Chernikov } 429ac35ff17SAlexander V. Chernikov 430ac35ff17SAlexander V. Chernikov int 431ac35ff17SAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 432ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 433ac35ff17SAlexander V. Chernikov { 434ac35ff17SAlexander V. Chernikov int error; 435ac35ff17SAlexander V. Chernikov struct _ipfw_obj_header *oh; 436ac35ff17SAlexander V. Chernikov struct tid_info ti; 437ac35ff17SAlexander V. Chernikov 438ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh)) 439ac35ff17SAlexander V. Chernikov return (EINVAL); 440ac35ff17SAlexander V. Chernikov 441ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)op3; 442ac35ff17SAlexander V. Chernikov objheader_to_ti(oh, &ti); 443ac35ff17SAlexander V. Chernikov 4441832a7b3SAlexander V. Chernikov if (op3->opcode == IP_FW_TABLE_XDESTROY) 445ac35ff17SAlexander V. Chernikov error = destroy_table(ch, &ti); 4461832a7b3SAlexander V. Chernikov else if (op3->opcode == IP_FW_TABLE_XFLUSH) 447ac35ff17SAlexander V. Chernikov error = flush_table(ch, &ti); 448ac35ff17SAlexander V. Chernikov else 449ac35ff17SAlexander V. Chernikov return (ENOTSUP); 450ac35ff17SAlexander V. Chernikov 451ac35ff17SAlexander V. Chernikov return (error); 4523b3a8eb9SGleb Smirnoff } 4533b3a8eb9SGleb Smirnoff 454b074b7bbSAlexander V. Chernikov /* 4559f7d47b0SAlexander V. Chernikov * Flushes all entries in given table. 456ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 457ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 458ac35ff17SAlexander V. Chernikov * 459ac35ff17SAlexander V. Chernikov * Returns 0 on success 460b074b7bbSAlexander V. Chernikov */ 4611832a7b3SAlexander V. Chernikov int 462ac35ff17SAlexander V. Chernikov flush_table(struct ip_fw_chain *ch, struct tid_info *ti) 4633b3a8eb9SGleb Smirnoff { 464b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 465b074b7bbSAlexander V. Chernikov struct table_config *tc; 4669f7d47b0SAlexander V. Chernikov struct table_algo *ta; 4679f7d47b0SAlexander V. Chernikov struct table_info ti_old, ti_new, *tablestate; 4689f7d47b0SAlexander V. Chernikov void *astate_old, *astate_new; 469b074b7bbSAlexander V. Chernikov int error; 470b074b7bbSAlexander V. Chernikov uint16_t kidx; 4713b3a8eb9SGleb Smirnoff 4723b3a8eb9SGleb Smirnoff /* 4739f7d47b0SAlexander V. Chernikov * Stage 1: save table algoritm. 474b074b7bbSAlexander V. Chernikov * Reference found table to ensure it won't disappear. 4753b3a8eb9SGleb Smirnoff */ 476b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 477b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 478b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 479b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 480b074b7bbSAlexander V. Chernikov return (ESRCH); 481b074b7bbSAlexander V. Chernikov } 4829f7d47b0SAlexander V. Chernikov ta = tc->ta; 483b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 484b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 4853b3a8eb9SGleb Smirnoff 486b074b7bbSAlexander V. Chernikov /* 4879f7d47b0SAlexander V. Chernikov * Stage 2: allocate new table instance using same algo. 4889490a627SAlexander V. Chernikov * TODO: pass startup parametes somehow. 489b074b7bbSAlexander V. Chernikov */ 4909f7d47b0SAlexander V. Chernikov memset(&ti_new, 0, sizeof(struct table_info)); 4919490a627SAlexander V. Chernikov if ((error = ta->init(&astate_new, &ti_new, NULL)) != 0) { 492b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 493b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 494b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 495b074b7bbSAlexander V. Chernikov return (error); 496b074b7bbSAlexander V. Chernikov } 497b074b7bbSAlexander V. Chernikov 498b074b7bbSAlexander V. Chernikov /* 499b074b7bbSAlexander V. Chernikov * Stage 3: swap old state pointers with newly-allocated ones. 500b074b7bbSAlexander V. Chernikov * Decrease refcount. 501b074b7bbSAlexander V. Chernikov */ 502b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 503b074b7bbSAlexander V. Chernikov 504b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 505b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 5069f7d47b0SAlexander V. Chernikov tablestate = (struct table_info *)ch->tablestate; 507b074b7bbSAlexander V. Chernikov 5089f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 5099f7d47b0SAlexander V. Chernikov ti_old = tablestate[kidx]; 5109f7d47b0SAlexander V. Chernikov tablestate[kidx] = ti_new; 5119f7d47b0SAlexander V. Chernikov IPFW_WUNLOCK(ch); 512b074b7bbSAlexander V. Chernikov 5139f7d47b0SAlexander V. Chernikov astate_old = tc->astate; 5149f7d47b0SAlexander V. Chernikov tc->astate = astate_new; 5159f7d47b0SAlexander V. Chernikov tc->ti = ti_new; 5169f7d47b0SAlexander V. Chernikov tc->count = 0; 517b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 518b074b7bbSAlexander V. Chernikov 519b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 5203b3a8eb9SGleb Smirnoff 521b074b7bbSAlexander V. Chernikov /* 522b074b7bbSAlexander V. Chernikov * Stage 4: perform real flush. 523b074b7bbSAlexander V. Chernikov */ 5249f7d47b0SAlexander V. Chernikov ta->destroy(astate_old, &ti_old); 5253b3a8eb9SGleb Smirnoff 5263b3a8eb9SGleb Smirnoff return (0); 5273b3a8eb9SGleb Smirnoff } 5283b3a8eb9SGleb Smirnoff 529b074b7bbSAlexander V. Chernikov /* 5309f7d47b0SAlexander V. Chernikov * Destroys table specified by @ti. 531ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 532ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 533ac35ff17SAlexander V. Chernikov * 534ac35ff17SAlexander V. Chernikov * Returns 0 on success 535b074b7bbSAlexander V. Chernikov */ 536ac35ff17SAlexander V. Chernikov static int 537ac35ff17SAlexander V. Chernikov destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) 538b074b7bbSAlexander V. Chernikov { 539b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 540b074b7bbSAlexander V. Chernikov struct table_config *tc; 541b074b7bbSAlexander V. Chernikov 542b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 543b074b7bbSAlexander V. Chernikov 544b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 545b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 546b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 547b074b7bbSAlexander V. Chernikov return (ESRCH); 548b074b7bbSAlexander V. Chernikov } 549b074b7bbSAlexander V. Chernikov 5509f7d47b0SAlexander V. Chernikov /* Do not permit destroying referenced tables */ 5519f7d47b0SAlexander V. Chernikov if (tc->no.refcnt > 0) { 552b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 553b074b7bbSAlexander V. Chernikov return (EBUSY); 554b074b7bbSAlexander V. Chernikov } 555b074b7bbSAlexander V. Chernikov 556b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 557b074b7bbSAlexander V. Chernikov unlink_table(ch, tc); 558b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 559b074b7bbSAlexander V. Chernikov 560b074b7bbSAlexander V. Chernikov /* Free obj index */ 561ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0) 562b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 563b074b7bbSAlexander V. Chernikov tc->no.kidx, tc->tablename); 564b074b7bbSAlexander V. Chernikov 565b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 566b074b7bbSAlexander V. Chernikov 567b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 568b074b7bbSAlexander V. Chernikov 569b074b7bbSAlexander V. Chernikov return (0); 570b074b7bbSAlexander V. Chernikov } 571b074b7bbSAlexander V. Chernikov 572b074b7bbSAlexander V. Chernikov static void 573b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, 574b074b7bbSAlexander V. Chernikov void *arg) 575b074b7bbSAlexander V. Chernikov { 576b074b7bbSAlexander V. Chernikov 577b074b7bbSAlexander V. Chernikov unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); 578ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, no->kidx) != 0) 579b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 580b074b7bbSAlexander V. Chernikov no->kidx, no->name); 581b074b7bbSAlexander V. Chernikov free_table_config(ni, (struct table_config *)no); 582b074b7bbSAlexander V. Chernikov } 583b074b7bbSAlexander V. Chernikov 5843b3a8eb9SGleb Smirnoff void 5853b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch) 5863b3a8eb9SGleb Smirnoff { 5873b3a8eb9SGleb Smirnoff 588b074b7bbSAlexander V. Chernikov /* Remove all tables from working set */ 589b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 590b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 591b074b7bbSAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); 592b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 593b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 5943b3a8eb9SGleb Smirnoff 5953b3a8eb9SGleb Smirnoff /* Free pointers itself */ 5969f7d47b0SAlexander V. Chernikov free(ch->tablestate, M_IPFW); 5979f7d47b0SAlexander V. Chernikov 5989f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(ch); 599b074b7bbSAlexander V. Chernikov 600b074b7bbSAlexander V. Chernikov ipfw_objhash_destroy(CHAIN_TO_NI(ch)); 601b074b7bbSAlexander V. Chernikov free(CHAIN_TO_TCFG(ch), M_IPFW); 6023b3a8eb9SGleb Smirnoff } 6033b3a8eb9SGleb Smirnoff 6043b3a8eb9SGleb Smirnoff int 6053b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch) 6063b3a8eb9SGleb Smirnoff { 607b074b7bbSAlexander V. Chernikov struct tables_config *tcfg; 608b074b7bbSAlexander V. Chernikov 6093b3a8eb9SGleb Smirnoff /* Allocate pointers */ 6109f7d47b0SAlexander V. Chernikov ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), 6119f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 612b074b7bbSAlexander V. Chernikov 613b074b7bbSAlexander V. Chernikov tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); 614b074b7bbSAlexander V. Chernikov tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); 615b074b7bbSAlexander V. Chernikov ch->tblcfg = tcfg; 616b074b7bbSAlexander V. Chernikov 6179f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(ch); 6189f7d47b0SAlexander V. Chernikov 6193b3a8eb9SGleb Smirnoff return (0); 6203b3a8eb9SGleb Smirnoff } 6213b3a8eb9SGleb Smirnoff 6223b3a8eb9SGleb Smirnoff int 6233b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) 6243b3a8eb9SGleb Smirnoff { 6253b3a8eb9SGleb Smirnoff unsigned int ntables_old, tbl; 626b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 6279f7d47b0SAlexander V. Chernikov void *new_idx, *old_tablestate, *tablestate; 628b074b7bbSAlexander V. Chernikov int new_blocks; 6293b3a8eb9SGleb Smirnoff 6303b3a8eb9SGleb Smirnoff /* Check new value for validity */ 6313b3a8eb9SGleb Smirnoff if (ntables > IPFW_TABLES_MAX) 6323b3a8eb9SGleb Smirnoff ntables = IPFW_TABLES_MAX; 6333b3a8eb9SGleb Smirnoff 6343b3a8eb9SGleb Smirnoff /* Allocate new pointers */ 6359f7d47b0SAlexander V. Chernikov tablestate = malloc(ntables * sizeof(struct table_info), 6369f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 6379f7d47b0SAlexander V. Chernikov 638b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); 6393b3a8eb9SGleb Smirnoff 6409f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 6413b3a8eb9SGleb Smirnoff 6423b3a8eb9SGleb Smirnoff tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables; 643b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 644b074b7bbSAlexander V. Chernikov 6459f7d47b0SAlexander V. Chernikov /* Temporary restrict decreasing max_tables */ 6469f7d47b0SAlexander V. Chernikov if (ntables < V_fw_tables_max) { 6479f7d47b0SAlexander V. Chernikov 6489f7d47b0SAlexander V. Chernikov /* 6499f7d47b0SAlexander V. Chernikov * FIXME: Check if we really can shrink 6509f7d47b0SAlexander V. Chernikov */ 6519f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 652b074b7bbSAlexander V. Chernikov return (EINVAL); 653b074b7bbSAlexander V. Chernikov } 6543b3a8eb9SGleb Smirnoff 6559f7d47b0SAlexander V. Chernikov /* Copy table info/indices */ 6569f7d47b0SAlexander V. Chernikov memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl); 6579f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks); 6583b3a8eb9SGleb Smirnoff 6599f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 6609f7d47b0SAlexander V. Chernikov 6619f7d47b0SAlexander V. Chernikov /* Change pointers */ 6629f7d47b0SAlexander V. Chernikov old_tablestate = ch->tablestate; 6639f7d47b0SAlexander V. Chernikov ch->tablestate = tablestate; 6649f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks); 6653b3a8eb9SGleb Smirnoff 6663b3a8eb9SGleb Smirnoff ntables_old = V_fw_tables_max; 6673b3a8eb9SGleb Smirnoff V_fw_tables_max = ntables; 6683b3a8eb9SGleb Smirnoff 6693b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 6709f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 6713b3a8eb9SGleb Smirnoff 6723b3a8eb9SGleb Smirnoff /* Free old pointers */ 6739f7d47b0SAlexander V. Chernikov free(old_tablestate, M_IPFW); 674b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 6753b3a8eb9SGleb Smirnoff 6763b3a8eb9SGleb Smirnoff return (0); 6773b3a8eb9SGleb Smirnoff } 6783b3a8eb9SGleb Smirnoff 6793b3a8eb9SGleb Smirnoff int 6803b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 6813b3a8eb9SGleb Smirnoff uint32_t *val) 6823b3a8eb9SGleb Smirnoff { 6839f7d47b0SAlexander V. Chernikov struct table_info *ti; 6843b3a8eb9SGleb Smirnoff 6859f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 6869f7d47b0SAlexander V. Chernikov 6879f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, &addr, sizeof(in_addr_t), val)); 6883b3a8eb9SGleb Smirnoff } 6899f7d47b0SAlexander V. Chernikov 6909f7d47b0SAlexander V. Chernikov int 6919f7d47b0SAlexander V. Chernikov ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, 6929f7d47b0SAlexander V. Chernikov void *paddr, uint32_t *val) 6939f7d47b0SAlexander V. Chernikov { 6949f7d47b0SAlexander V. Chernikov struct table_info *ti; 6959f7d47b0SAlexander V. Chernikov 6969f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 6979f7d47b0SAlexander V. Chernikov 6989f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, paddr, plen, val)); 6999f7d47b0SAlexander V. Chernikov } 7009f7d47b0SAlexander V. Chernikov 7019f7d47b0SAlexander V. Chernikov /* 7029f7d47b0SAlexander V. Chernikov * Info/List/dump support for tables. 7039f7d47b0SAlexander V. Chernikov * 7049f7d47b0SAlexander V. Chernikov */ 7059f7d47b0SAlexander V. Chernikov 706f1220db8SAlexander V. Chernikov /* 707d3a4f924SAlexander V. Chernikov * High-level 'get' cmds sysctl handlers 708d3a4f924SAlexander V. Chernikov */ 709d3a4f924SAlexander V. Chernikov 710d3a4f924SAlexander V. Chernikov /* 711d3a4f924SAlexander V. Chernikov * Get buffer size needed to list info for all tables. 712ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 713d3a4f924SAlexander V. Chernikov * Request: [ empty ], size = sizeof(ipfw_obj_lheader) 714d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ] 715d3a4f924SAlexander V. Chernikov * 716d3a4f924SAlexander V. Chernikov * Returns 0 on success 717f1220db8SAlexander V. Chernikov */ 718f1220db8SAlexander V. Chernikov int 7192d99a349SAlexander V. Chernikov ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 720f1220db8SAlexander V. Chernikov { 721f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 722f1220db8SAlexander V. Chernikov 7232d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 7242d99a349SAlexander V. Chernikov if (olh == NULL) 725d3a4f924SAlexander V. Chernikov return (EINVAL); 726d3a4f924SAlexander V. Chernikov 727f1220db8SAlexander V. Chernikov olh->size = sizeof(*olh); /* Make export_table store needed size */ 728f1220db8SAlexander V. Chernikov 729f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 7302d99a349SAlexander V. Chernikov export_tables(ch, olh, sd); 731f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 732f1220db8SAlexander V. Chernikov 7332d99a349SAlexander V. Chernikov return (0); 734f1220db8SAlexander V. Chernikov } 735f1220db8SAlexander V. Chernikov 736d3a4f924SAlexander V. Chernikov /* 737d3a4f924SAlexander V. Chernikov * Lists all tables currently available in kernel. 738ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 739d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 740d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ] 741d3a4f924SAlexander V. Chernikov * 742d3a4f924SAlexander V. Chernikov * Returns 0 on success 743d3a4f924SAlexander V. Chernikov */ 744f1220db8SAlexander V. Chernikov int 7452d99a349SAlexander V. Chernikov ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 746f1220db8SAlexander V. Chernikov { 747f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 748d3a4f924SAlexander V. Chernikov uint32_t sz; 749f1220db8SAlexander V. Chernikov int error; 750f1220db8SAlexander V. Chernikov 7512d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 7522d99a349SAlexander V. Chernikov if (olh == NULL) 753d3a4f924SAlexander V. Chernikov return (EINVAL); 754d3a4f924SAlexander V. Chernikov 755f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 756f1220db8SAlexander V. Chernikov sz = ipfw_objhash_count(CHAIN_TO_NI(ch)); 7572d99a349SAlexander V. Chernikov 7582d99a349SAlexander V. Chernikov if (sd->valsize < sz) { 7592d99a349SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 7602d99a349SAlexander V. Chernikov return (ENOMEM); 7612d99a349SAlexander V. Chernikov } 7622d99a349SAlexander V. Chernikov 7632d99a349SAlexander V. Chernikov error = export_tables(ch, olh, sd); 764f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 765f1220db8SAlexander V. Chernikov 766f1220db8SAlexander V. Chernikov return (error); 767f1220db8SAlexander V. Chernikov } 768f1220db8SAlexander V. Chernikov 769f1220db8SAlexander V. Chernikov /* 7702d99a349SAlexander V. Chernikov * Store table info to buffer provided by @sd. 771ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 772d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info(empty)] 773d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ] 774d3a4f924SAlexander V. Chernikov * 775d3a4f924SAlexander V. Chernikov * Returns 0 on success. 776d3a4f924SAlexander V. Chernikov */ 777d3a4f924SAlexander V. Chernikov int 7782d99a349SAlexander V. Chernikov ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd) 779d3a4f924SAlexander V. Chernikov { 780d3a4f924SAlexander V. Chernikov struct _ipfw_obj_header *oh; 781d3a4f924SAlexander V. Chernikov struct table_config *tc; 782d3a4f924SAlexander V. Chernikov struct tid_info ti; 783d3a4f924SAlexander V. Chernikov size_t sz; 784d3a4f924SAlexander V. Chernikov 785d3a4f924SAlexander V. Chernikov sz = sizeof(*oh) + sizeof(ipfw_xtable_info); 7862d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 7872d99a349SAlexander V. Chernikov if (oh == NULL) 788d3a4f924SAlexander V. Chernikov return (EINVAL); 789d3a4f924SAlexander V. Chernikov 790d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 791d3a4f924SAlexander V. Chernikov 792d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 793d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 794d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 795d3a4f924SAlexander V. Chernikov return (ESRCH); 796d3a4f924SAlexander V. Chernikov } 797d3a4f924SAlexander V. Chernikov 798ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, (ipfw_xtable_info *)(oh + 1)); 799d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 800d3a4f924SAlexander V. Chernikov 8012d99a349SAlexander V. Chernikov return (0); 802d3a4f924SAlexander V. Chernikov } 803d3a4f924SAlexander V. Chernikov 804f1220db8SAlexander V. Chernikov struct dump_args { 805f1220db8SAlexander V. Chernikov struct table_info *ti; 806f1220db8SAlexander V. Chernikov struct table_config *tc; 8072d99a349SAlexander V. Chernikov struct sockopt_data *sd; 808f1220db8SAlexander V. Chernikov uint32_t cnt; 809f1220db8SAlexander V. Chernikov uint16_t uidx; 8102d99a349SAlexander V. Chernikov ipfw_table_entry *ent; 8112d99a349SAlexander V. Chernikov uint32_t size; 812f1220db8SAlexander V. Chernikov }; 813f1220db8SAlexander V. Chernikov 814f1220db8SAlexander V. Chernikov int 8152d99a349SAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 8162d99a349SAlexander V. Chernikov struct sockopt_data *sd) 817f1220db8SAlexander V. Chernikov { 818d3a4f924SAlexander V. Chernikov int error; 819d3a4f924SAlexander V. Chernikov 820d3a4f924SAlexander V. Chernikov switch (op3->version) { 821d3a4f924SAlexander V. Chernikov case 0: 8222d99a349SAlexander V. Chernikov error = ipfw_dump_table_v0(ch, sd); 823d3a4f924SAlexander V. Chernikov break; 824d3a4f924SAlexander V. Chernikov case 1: 8252d99a349SAlexander V. Chernikov error = ipfw_dump_table_v1(ch, sd); 826d3a4f924SAlexander V. Chernikov break; 827d3a4f924SAlexander V. Chernikov default: 828d3a4f924SAlexander V. Chernikov error = ENOTSUP; 829d3a4f924SAlexander V. Chernikov } 830d3a4f924SAlexander V. Chernikov 831d3a4f924SAlexander V. Chernikov return (error); 832d3a4f924SAlexander V. Chernikov } 833d3a4f924SAlexander V. Chernikov 834d3a4f924SAlexander V. Chernikov /* 835d3a4f924SAlexander V. Chernikov * Dumps all table data 836ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 8372d99a349SAlexander V. Chernikov * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size 8382d99a349SAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_table_xentry x N ] 839d3a4f924SAlexander V. Chernikov * 840d3a4f924SAlexander V. Chernikov * Returns 0 on success 841d3a4f924SAlexander V. Chernikov */ 842d3a4f924SAlexander V. Chernikov static int 8432d99a349SAlexander V. Chernikov ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd) 844d3a4f924SAlexander V. Chernikov { 845f1220db8SAlexander V. Chernikov struct _ipfw_obj_header *oh; 846f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 847f1220db8SAlexander V. Chernikov struct tid_info ti; 848f1220db8SAlexander V. Chernikov struct table_config *tc; 849f1220db8SAlexander V. Chernikov struct table_algo *ta; 850f1220db8SAlexander V. Chernikov struct dump_args da; 851d3a4f924SAlexander V. Chernikov uint32_t sz; 852f1220db8SAlexander V. Chernikov 8532d99a349SAlexander V. Chernikov sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 8542d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 8552d99a349SAlexander V. Chernikov if (oh == NULL) 856d3a4f924SAlexander V. Chernikov return (EINVAL); 857d3a4f924SAlexander V. Chernikov 8582d99a349SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 859d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 860f1220db8SAlexander V. Chernikov 861f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 862f1220db8SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 863f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 864f1220db8SAlexander V. Chernikov return (ESRCH); 865f1220db8SAlexander V. Chernikov } 866ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, i); 8672d99a349SAlexander V. Chernikov sz = tc->count; 8682d99a349SAlexander V. Chernikov 8692d99a349SAlexander V. Chernikov if (sd->valsize < sz + tc->count * sizeof(ipfw_table_xentry)) { 8702d99a349SAlexander V. Chernikov 8712d99a349SAlexander V. Chernikov /* 8722d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 8732d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 8742d99a349SAlexander V. Chernikov * relevant table info including size, so we 8752d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 8762d99a349SAlexander V. Chernikov */ 877f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 8782d99a349SAlexander V. Chernikov return (ENOMEM); 879f1220db8SAlexander V. Chernikov } 880f1220db8SAlexander V. Chernikov 881f1220db8SAlexander V. Chernikov /* 882f1220db8SAlexander V. Chernikov * Do the actual dump in eXtended format 883f1220db8SAlexander V. Chernikov */ 884d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 885f1220db8SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 886f1220db8SAlexander V. Chernikov da.tc = tc; 8872d99a349SAlexander V. Chernikov da.sd = sd; 888f1220db8SAlexander V. Chernikov 889f1220db8SAlexander V. Chernikov ta = tc->ta; 890f1220db8SAlexander V. Chernikov 891f1220db8SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 892f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 893f1220db8SAlexander V. Chernikov 894f1220db8SAlexander V. Chernikov return (0); 895f1220db8SAlexander V. Chernikov } 896f1220db8SAlexander V. Chernikov 897d3a4f924SAlexander V. Chernikov /* 898d3a4f924SAlexander V. Chernikov * Dumps all table data 8992d99a349SAlexander V. Chernikov * Data layout (version 0)(legacy): 900d3a4f924SAlexander V. Chernikov * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE() 901d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_xtable ipfw_table_xentry x N ] 902d3a4f924SAlexander V. Chernikov * 903d3a4f924SAlexander V. Chernikov * Returns 0 on success 904d3a4f924SAlexander V. Chernikov */ 905d3a4f924SAlexander V. Chernikov static int 9062d99a349SAlexander V. Chernikov ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd) 907d3a4f924SAlexander V. Chernikov { 908d3a4f924SAlexander V. Chernikov ipfw_xtable *xtbl; 909d3a4f924SAlexander V. Chernikov struct tid_info ti; 910d3a4f924SAlexander V. Chernikov struct table_config *tc; 911d3a4f924SAlexander V. Chernikov struct table_algo *ta; 912d3a4f924SAlexander V. Chernikov struct dump_args da; 913d3a4f924SAlexander V. Chernikov size_t sz; 914d3a4f924SAlexander V. Chernikov 9152d99a349SAlexander V. Chernikov xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable)); 9162d99a349SAlexander V. Chernikov if (xtbl == NULL) 917d3a4f924SAlexander V. Chernikov return (EINVAL); 918d3a4f924SAlexander V. Chernikov 919d3a4f924SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 920d3a4f924SAlexander V. Chernikov ti.uidx = xtbl->tbl; 921d3a4f924SAlexander V. Chernikov 922d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 923d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 924d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 925d3a4f924SAlexander V. Chernikov return (0); 926d3a4f924SAlexander V. Chernikov } 927d3a4f924SAlexander V. Chernikov sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); 9282d99a349SAlexander V. Chernikov 9292d99a349SAlexander V. Chernikov xtbl->cnt = tc->count; 9302d99a349SAlexander V. Chernikov xtbl->size = sz; 9312d99a349SAlexander V. Chernikov xtbl->type = tc->no.type; 9322d99a349SAlexander V. Chernikov xtbl->tbl = ti.uidx; 9332d99a349SAlexander V. Chernikov 9342d99a349SAlexander V. Chernikov if (sd->valsize < sz) { 9352d99a349SAlexander V. Chernikov 9362d99a349SAlexander V. Chernikov /* 9372d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 9382d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 9392d99a349SAlexander V. Chernikov * relevant table info including size, so we 9402d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 9412d99a349SAlexander V. Chernikov */ 942d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 9432d99a349SAlexander V. Chernikov return (ENOMEM); 944d3a4f924SAlexander V. Chernikov } 945d3a4f924SAlexander V. Chernikov 946d3a4f924SAlexander V. Chernikov /* Do the actual dump in eXtended format */ 947d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 948d3a4f924SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 949d3a4f924SAlexander V. Chernikov da.tc = tc; 9502d99a349SAlexander V. Chernikov da.sd = sd; 9512d99a349SAlexander V. Chernikov 952d3a4f924SAlexander V. Chernikov ta = tc->ta; 953d3a4f924SAlexander V. Chernikov 954d3a4f924SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 955d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 956d3a4f924SAlexander V. Chernikov 9572d99a349SAlexander V. Chernikov return (0); 958d3a4f924SAlexander V. Chernikov } 959d3a4f924SAlexander V. Chernikov 960d3a4f924SAlexander V. Chernikov /* 9619490a627SAlexander V. Chernikov * Creates new table. 962ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 9639490a627SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 9649490a627SAlexander V. Chernikov * 9659490a627SAlexander V. Chernikov * Returns 0 on success 9669490a627SAlexander V. Chernikov */ 9679490a627SAlexander V. Chernikov int 968ac35ff17SAlexander V. Chernikov ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 969ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 9709490a627SAlexander V. Chernikov { 9719490a627SAlexander V. Chernikov struct _ipfw_obj_header *oh; 9729490a627SAlexander V. Chernikov ipfw_xtable_info *i; 9739490a627SAlexander V. Chernikov char *tname, *aname; 9749490a627SAlexander V. Chernikov struct tid_info ti; 9759490a627SAlexander V. Chernikov struct namedobj_instance *ni; 9769490a627SAlexander V. Chernikov struct table_config *tc; 9779490a627SAlexander V. Chernikov struct table_algo *ta; 9789490a627SAlexander V. Chernikov uint16_t kidx; 9799490a627SAlexander V. Chernikov 980ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info)) 9819490a627SAlexander V. Chernikov return (EINVAL); 9829490a627SAlexander V. Chernikov 983ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)sd->kbuf; 9849490a627SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 9859490a627SAlexander V. Chernikov 9869490a627SAlexander V. Chernikov /* 9879490a627SAlexander V. Chernikov * Verify user-supplied strings. 9882d99a349SAlexander V. Chernikov * Check for null-terminated/zero-length strings/ 9899490a627SAlexander V. Chernikov */ 990ac35ff17SAlexander V. Chernikov tname = oh->ntlv.name; 9919490a627SAlexander V. Chernikov aname = i->algoname; 992ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(tname) != 0 || 9939490a627SAlexander V. Chernikov strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname)) 9949490a627SAlexander V. Chernikov return (EINVAL); 9959490a627SAlexander V. Chernikov 9969490a627SAlexander V. Chernikov if (aname[0] == '\0') { 9979490a627SAlexander V. Chernikov /* Use default algorithm */ 9989490a627SAlexander V. Chernikov aname = NULL; 9999490a627SAlexander V. Chernikov } 10009490a627SAlexander V. Chernikov 10019490a627SAlexander V. Chernikov objheader_to_ti(oh, &ti); 1002ac35ff17SAlexander V. Chernikov ti.type = i->type; 10039490a627SAlexander V. Chernikov 10049490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 10059490a627SAlexander V. Chernikov 10069490a627SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 10079490a627SAlexander V. Chernikov if ((tc = find_table(ni, &ti)) != NULL) { 10089490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 10099490a627SAlexander V. Chernikov return (EEXIST); 10109490a627SAlexander V. Chernikov } 10119490a627SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(ch), &ti, aname); 10129490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 10139490a627SAlexander V. Chernikov 10149490a627SAlexander V. Chernikov if (ta == NULL) 10159490a627SAlexander V. Chernikov return (ENOTSUP); 10169490a627SAlexander V. Chernikov 10179490a627SAlexander V. Chernikov if ((tc = alloc_table_config(ni, &ti, ta, aname)) == NULL) 10189490a627SAlexander V. Chernikov return (ENOMEM); 1019ac35ff17SAlexander V. Chernikov /* TODO: move inside alloc_table_config() */ 1020ac35ff17SAlexander V. Chernikov tc->vtype = i->vtype; 10219490a627SAlexander V. Chernikov 10229490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1023ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) { 10249490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 10259490a627SAlexander V. Chernikov printf("Unable to allocate table index for table %s in set %u." 10269490a627SAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 10279490a627SAlexander V. Chernikov tname, ti.set); 10289490a627SAlexander V. Chernikov free_table_config(ni, tc); 10299490a627SAlexander V. Chernikov return (EBUSY); 10309490a627SAlexander V. Chernikov } 10319490a627SAlexander V. Chernikov 10329490a627SAlexander V. Chernikov tc->no.kidx = kidx; 10339490a627SAlexander V. Chernikov 10349490a627SAlexander V. Chernikov IPFW_WLOCK(ch); 10359490a627SAlexander V. Chernikov link_table(ch, tc); 10369490a627SAlexander V. Chernikov IPFW_WUNLOCK(ch); 10379490a627SAlexander V. Chernikov 10389490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 10399490a627SAlexander V. Chernikov 10409490a627SAlexander V. Chernikov return (0); 10419490a627SAlexander V. Chernikov } 10429490a627SAlexander V. Chernikov 1043d3a4f924SAlexander V. Chernikov void 1044d3a4f924SAlexander V. Chernikov objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti) 1045d3a4f924SAlexander V. Chernikov { 1046d3a4f924SAlexander V. Chernikov 1047d3a4f924SAlexander V. Chernikov memset(ti, 0, sizeof(struct tid_info)); 1048d3a4f924SAlexander V. Chernikov ti->set = oh->set; 1049d3a4f924SAlexander V. Chernikov ti->uidx = oh->idx; 1050d3a4f924SAlexander V. Chernikov ti->tlvs = &oh->ntlv; 1051d3a4f924SAlexander V. Chernikov ti->tlen = oh->ntlv.head.length; 1052d3a4f924SAlexander V. Chernikov } 1053d3a4f924SAlexander V. Chernikov 1054563b5ab1SAlexander V. Chernikov int 1055563b5ab1SAlexander V. Chernikov ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx, 1056563b5ab1SAlexander V. Chernikov struct sockopt_data *sd) 1057563b5ab1SAlexander V. Chernikov { 1058563b5ab1SAlexander V. Chernikov struct namedobj_instance *ni; 1059563b5ab1SAlexander V. Chernikov struct named_object *no; 1060563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1061563b5ab1SAlexander V. Chernikov 1062563b5ab1SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1063563b5ab1SAlexander V. Chernikov 1064ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 1065563b5ab1SAlexander V. Chernikov KASSERT(no != NULL, ("invalid table kidx passed")); 1066563b5ab1SAlexander V. Chernikov 1067563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 1068563b5ab1SAlexander V. Chernikov if (ntlv == NULL) 1069563b5ab1SAlexander V. Chernikov return (ENOMEM); 1070563b5ab1SAlexander V. Chernikov 1071563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 1072563b5ab1SAlexander V. Chernikov ntlv->head.length = sizeof(*ntlv); 1073563b5ab1SAlexander V. Chernikov ntlv->idx = no->kidx; 1074563b5ab1SAlexander V. Chernikov strlcpy(ntlv->name, no->name, sizeof(ntlv->name)); 1075563b5ab1SAlexander V. Chernikov 1076563b5ab1SAlexander V. Chernikov return (0); 1077563b5ab1SAlexander V. Chernikov } 1078563b5ab1SAlexander V. Chernikov 10799f7d47b0SAlexander V. Chernikov static void 1080ac35ff17SAlexander V. Chernikov export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 1081ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i) 10829f7d47b0SAlexander V. Chernikov { 1083ac35ff17SAlexander V. Chernikov struct table_info *ti; 10849f7d47b0SAlexander V. Chernikov 10859f7d47b0SAlexander V. Chernikov i->type = tc->no.type; 1086ac35ff17SAlexander V. Chernikov i->vtype = tc->vtype; 10879f7d47b0SAlexander V. Chernikov i->set = tc->no.set; 10889f7d47b0SAlexander V. Chernikov i->kidx = tc->no.kidx; 10899f7d47b0SAlexander V. Chernikov i->refcnt = tc->no.refcnt; 10909f7d47b0SAlexander V. Chernikov i->count = tc->count; 10919f7d47b0SAlexander V. Chernikov i->size = tc->count * sizeof(ipfw_table_xentry); 1092f1220db8SAlexander V. Chernikov i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 10939f7d47b0SAlexander V. Chernikov strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); 1094ac35ff17SAlexander V. Chernikov if (tc->ta->print_config != NULL) { 1095ac35ff17SAlexander V. Chernikov /* Use algo function to print table config to string */ 1096ac35ff17SAlexander V. Chernikov ti = KIDX_TO_TI(ch, tc->no.kidx); 1097ac35ff17SAlexander V. Chernikov tc->ta->print_config(tc->astate, ti, i->algoname, 1098ac35ff17SAlexander V. Chernikov sizeof(i->algoname)); 1099ac35ff17SAlexander V. Chernikov } else 1100ac35ff17SAlexander V. Chernikov strlcpy(i->algoname, tc->ta->name, sizeof(i->algoname)); 11019f7d47b0SAlexander V. Chernikov } 11029f7d47b0SAlexander V. Chernikov 1103ac35ff17SAlexander V. Chernikov struct dump_table_args { 1104ac35ff17SAlexander V. Chernikov struct ip_fw_chain *ch; 1105ac35ff17SAlexander V. Chernikov struct sockopt_data *sd; 1106ac35ff17SAlexander V. Chernikov }; 1107ac35ff17SAlexander V. Chernikov 11089f7d47b0SAlexander V. Chernikov static void 11099f7d47b0SAlexander V. Chernikov export_table_internal(struct namedobj_instance *ni, struct named_object *no, 11109f7d47b0SAlexander V. Chernikov void *arg) 11113b3a8eb9SGleb Smirnoff { 11129f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i; 1113ac35ff17SAlexander V. Chernikov struct dump_table_args *dta; 11143b3a8eb9SGleb Smirnoff 1115ac35ff17SAlexander V. Chernikov dta = (struct dump_table_args *)arg; 1116ac35ff17SAlexander V. Chernikov 1117ac35ff17SAlexander V. Chernikov i = (ipfw_xtable_info *)ipfw_get_sopt_space(dta->sd, sizeof(*i)); 11182d99a349SAlexander V. Chernikov KASSERT(i == 0, ("previously checked buffer is not enough")); 11199f7d47b0SAlexander V. Chernikov 1120ac35ff17SAlexander V. Chernikov export_table_info(dta->ch, (struct table_config *)no, i); 11219f7d47b0SAlexander V. Chernikov } 11229f7d47b0SAlexander V. Chernikov 1123f1220db8SAlexander V. Chernikov /* 1124f1220db8SAlexander V. Chernikov * Export all tables as ipfw_xtable_info structures to 11252d99a349SAlexander V. Chernikov * storage provided by @sd. 1126f1220db8SAlexander V. Chernikov * Returns 0 on success. 1127f1220db8SAlexander V. Chernikov */ 1128f1220db8SAlexander V. Chernikov static int 11292d99a349SAlexander V. Chernikov export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 11302d99a349SAlexander V. Chernikov struct sockopt_data *sd) 11319f7d47b0SAlexander V. Chernikov { 11329f7d47b0SAlexander V. Chernikov uint32_t size; 11339f7d47b0SAlexander V. Chernikov uint32_t count; 1134ac35ff17SAlexander V. Chernikov struct dump_table_args dta; 11359f7d47b0SAlexander V. Chernikov 11369f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 11379f7d47b0SAlexander V. Chernikov size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 11382d99a349SAlexander V. Chernikov 11392d99a349SAlexander V. Chernikov /* Fill in header regadless of buffer size */ 1140f1220db8SAlexander V. Chernikov olh->count = count; 1141f1220db8SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 11422d99a349SAlexander V. Chernikov 11432d99a349SAlexander V. Chernikov if (size > olh->size) { 11442d99a349SAlexander V. Chernikov /* Store necessary size */ 11452d99a349SAlexander V. Chernikov olh->size = size; 11469f7d47b0SAlexander V. Chernikov return (ENOMEM); 1147f1220db8SAlexander V. Chernikov } 11489f7d47b0SAlexander V. Chernikov olh->size = size; 11492d99a349SAlexander V. Chernikov 1150ac35ff17SAlexander V. Chernikov dta.ch = ch; 1151ac35ff17SAlexander V. Chernikov dta.sd = sd; 1152ac35ff17SAlexander V. Chernikov 1153ac35ff17SAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, &dta); 11549f7d47b0SAlexander V. Chernikov 11553b3a8eb9SGleb Smirnoff return (0); 11563b3a8eb9SGleb Smirnoff } 11573b3a8eb9SGleb Smirnoff 11583b3a8eb9SGleb Smirnoff int 1159b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 11603b3a8eb9SGleb Smirnoff { 1161b074b7bbSAlexander V. Chernikov struct table_config *tc; 11623b3a8eb9SGleb Smirnoff 1163b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1164b074b7bbSAlexander V. Chernikov return (ESRCH); 11659f7d47b0SAlexander V. Chernikov *cnt = tc->count; 11663b3a8eb9SGleb Smirnoff return (0); 11673b3a8eb9SGleb Smirnoff } 11683b3a8eb9SGleb Smirnoff 11699f7d47b0SAlexander V. Chernikov 11709f7d47b0SAlexander V. Chernikov int 11719f7d47b0SAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 11723b3a8eb9SGleb Smirnoff { 11739f7d47b0SAlexander V. Chernikov struct table_config *tc; 11749f7d47b0SAlexander V. Chernikov 1175d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) { 1176d3a4f924SAlexander V. Chernikov *cnt = 0; 11779f7d47b0SAlexander V. Chernikov return (0); /* 'table all list' requires success */ 1178d3a4f924SAlexander V. Chernikov } 11799f7d47b0SAlexander V. Chernikov *cnt = tc->count * sizeof(ipfw_table_xentry); 11809f7d47b0SAlexander V. Chernikov if (tc->count > 0) 11819f7d47b0SAlexander V. Chernikov *cnt += sizeof(ipfw_xtable); 11829f7d47b0SAlexander V. Chernikov return (0); 11839f7d47b0SAlexander V. Chernikov } 11849f7d47b0SAlexander V. Chernikov 11859f7d47b0SAlexander V. Chernikov static int 11869f7d47b0SAlexander V. Chernikov dump_table_entry(void *e, void *arg) 11879f7d47b0SAlexander V. Chernikov { 11889f7d47b0SAlexander V. Chernikov struct dump_args *da; 11899f7d47b0SAlexander V. Chernikov struct table_config *tc; 11909f7d47b0SAlexander V. Chernikov struct table_algo *ta; 11913b3a8eb9SGleb Smirnoff ipfw_table_entry *ent; 11923b3a8eb9SGleb Smirnoff 11939f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 11949f7d47b0SAlexander V. Chernikov 11959f7d47b0SAlexander V. Chernikov tc = da->tc; 11969f7d47b0SAlexander V. Chernikov ta = tc->ta; 11979f7d47b0SAlexander V. Chernikov 11989f7d47b0SAlexander V. Chernikov /* Out of memory, returning */ 1199f1220db8SAlexander V. Chernikov if (da->cnt == da->size) 12003b3a8eb9SGleb Smirnoff return (1); 1201f1220db8SAlexander V. Chernikov ent = da->ent++; 1202f1220db8SAlexander V. Chernikov ent->tbl = da->uidx; 1203f1220db8SAlexander V. Chernikov da->cnt++; 12049f7d47b0SAlexander V. Chernikov 12059f7d47b0SAlexander V. Chernikov return (ta->dump_entry(tc->astate, da->ti, e, ent)); 12063b3a8eb9SGleb Smirnoff } 12073b3a8eb9SGleb Smirnoff 1208f1220db8SAlexander V. Chernikov /* 1209f1220db8SAlexander V. Chernikov * Dumps table in pre-8.1 legacy format. 1210f1220db8SAlexander V. Chernikov */ 12113b3a8eb9SGleb Smirnoff int 1212f1220db8SAlexander V. Chernikov ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti, 1213f1220db8SAlexander V. Chernikov ipfw_table *tbl) 12143b3a8eb9SGleb Smirnoff { 1215b074b7bbSAlexander V. Chernikov struct table_config *tc; 12169f7d47b0SAlexander V. Chernikov struct table_algo *ta; 12179f7d47b0SAlexander V. Chernikov struct dump_args da; 12183b3a8eb9SGleb Smirnoff 12193b3a8eb9SGleb Smirnoff tbl->cnt = 0; 12203b3a8eb9SGleb Smirnoff 1221b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1222b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 12239f7d47b0SAlexander V. Chernikov 12249f7d47b0SAlexander V. Chernikov ta = tc->ta; 12259f7d47b0SAlexander V. Chernikov 12269f7d47b0SAlexander V. Chernikov if (ta->dump_entry == NULL) 12279f7d47b0SAlexander V. Chernikov return (0); /* Legacy dump support is not necessary */ 12289f7d47b0SAlexander V. Chernikov 1229d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 12309f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 12319f7d47b0SAlexander V. Chernikov da.tc = tc; 1232f1220db8SAlexander V. Chernikov da.ent = &tbl->ent[0]; 1233f1220db8SAlexander V. Chernikov da.size = tbl->size; 12349f7d47b0SAlexander V. Chernikov 12359f7d47b0SAlexander V. Chernikov tbl->cnt = 0; 12369f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_entry, &da); 1237f1220db8SAlexander V. Chernikov tbl->cnt = da.cnt; 12389f7d47b0SAlexander V. Chernikov 12393b3a8eb9SGleb Smirnoff return (0); 12403b3a8eb9SGleb Smirnoff } 12413b3a8eb9SGleb Smirnoff 12429490a627SAlexander V. Chernikov /* 12439490a627SAlexander V. Chernikov * Dumps table entry in eXtended format (current). 12449490a627SAlexander V. Chernikov */ 12453b3a8eb9SGleb Smirnoff static int 12469f7d47b0SAlexander V. Chernikov dump_table_xentry(void *e, void *arg) 12473b3a8eb9SGleb Smirnoff { 12489f7d47b0SAlexander V. Chernikov struct dump_args *da; 12499f7d47b0SAlexander V. Chernikov struct table_config *tc; 12509f7d47b0SAlexander V. Chernikov struct table_algo *ta; 12513b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 12523b3a8eb9SGleb Smirnoff 12539f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 12549f7d47b0SAlexander V. Chernikov 12559f7d47b0SAlexander V. Chernikov tc = da->tc; 12569f7d47b0SAlexander V. Chernikov ta = tc->ta; 12579f7d47b0SAlexander V. Chernikov 12582d99a349SAlexander V. Chernikov xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent)); 12593b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 12602d99a349SAlexander V. Chernikov if (xent == NULL) 12613b3a8eb9SGleb Smirnoff return (1); 12623b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 1263f1220db8SAlexander V. Chernikov xent->tbl = da->uidx; 12649f7d47b0SAlexander V. Chernikov 12659f7d47b0SAlexander V. Chernikov return (ta->dump_xentry(tc->astate, da->ti, e, xent)); 12669f7d47b0SAlexander V. Chernikov } 12679f7d47b0SAlexander V. Chernikov 12689f7d47b0SAlexander V. Chernikov /* 12699f7d47b0SAlexander V. Chernikov * Table algorithms 12709f7d47b0SAlexander V. Chernikov */ 12713b3a8eb9SGleb Smirnoff 12729f7d47b0SAlexander V. Chernikov /* 12739490a627SAlexander V. Chernikov * Finds algoritm by index, table type or supplied name 12749f7d47b0SAlexander V. Chernikov */ 12759f7d47b0SAlexander V. Chernikov static struct table_algo * 12769490a627SAlexander V. Chernikov find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name) 12779f7d47b0SAlexander V. Chernikov { 12789490a627SAlexander V. Chernikov int i, l; 12799490a627SAlexander V. Chernikov struct table_algo *ta; 12809f7d47b0SAlexander V. Chernikov 12819f7d47b0SAlexander V. Chernikov /* Search by index */ 12829f7d47b0SAlexander V. Chernikov if (ti->atype != 0) { 12839f7d47b0SAlexander V. Chernikov if (ti->atype > tcfg->algo_count) 12849f7d47b0SAlexander V. Chernikov return (NULL); 12859f7d47b0SAlexander V. Chernikov return (tcfg->algo[ti->atype]); 12869f7d47b0SAlexander V. Chernikov } 12879f7d47b0SAlexander V. Chernikov 12889490a627SAlexander V. Chernikov /* Search by name if supplied */ 12899490a627SAlexander V. Chernikov if (name != NULL) { 12909490a627SAlexander V. Chernikov /* TODO: better search */ 12919490a627SAlexander V. Chernikov for (i = 1; i <= tcfg->algo_count; i++) { 12929490a627SAlexander V. Chernikov ta = tcfg->algo[i]; 12939490a627SAlexander V. Chernikov 12949490a627SAlexander V. Chernikov /* 12959490a627SAlexander V. Chernikov * One can supply additional algorithm 12969490a627SAlexander V. Chernikov * parameters so we compare only the first word 12979490a627SAlexander V. Chernikov * of supplied name: 12989490a627SAlexander V. Chernikov * 'hash_cidr hsize=32' 12999490a627SAlexander V. Chernikov * '^^^^^^^^^' 13009490a627SAlexander V. Chernikov * 13019490a627SAlexander V. Chernikov */ 13029490a627SAlexander V. Chernikov l = strlen(ta->name); 13039490a627SAlexander V. Chernikov if (strncmp(name, ta->name, l) == 0) { 13049490a627SAlexander V. Chernikov if (name[l] == '\0' || name[l] == ' ') 13059490a627SAlexander V. Chernikov return (ta); 13069490a627SAlexander V. Chernikov } 13079490a627SAlexander V. Chernikov } 13089490a627SAlexander V. Chernikov 13099490a627SAlexander V. Chernikov return (NULL); 13109490a627SAlexander V. Chernikov } 13119490a627SAlexander V. Chernikov 13129f7d47b0SAlexander V. Chernikov /* Search by type */ 13139f7d47b0SAlexander V. Chernikov switch (ti->type) { 13143b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 13159f7d47b0SAlexander V. Chernikov return (&radix_cidr); 13163b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 13179f7d47b0SAlexander V. Chernikov return (&radix_iface); 13183b3a8eb9SGleb Smirnoff } 13193b3a8eb9SGleb Smirnoff 13209f7d47b0SAlexander V. Chernikov return (NULL); 13213b3a8eb9SGleb Smirnoff } 13223b3a8eb9SGleb Smirnoff 13239f7d47b0SAlexander V. Chernikov void 13249f7d47b0SAlexander V. Chernikov ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta) 13253b3a8eb9SGleb Smirnoff { 13269f7d47b0SAlexander V. Chernikov struct tables_config *tcfg; 13273b3a8eb9SGleb Smirnoff 13289f7d47b0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 1329b074b7bbSAlexander V. Chernikov 13309f7d47b0SAlexander V. Chernikov KASSERT(tcfg->algo_count < 255, ("Increase algo array size")); 13319f7d47b0SAlexander V. Chernikov 13329f7d47b0SAlexander V. Chernikov tcfg->algo[++tcfg->algo_count] = ta; 13339f7d47b0SAlexander V. Chernikov ta->idx = tcfg->algo_count; 13343b3a8eb9SGleb Smirnoff } 13353b3a8eb9SGleb Smirnoff 13369f7d47b0SAlexander V. Chernikov 1337b074b7bbSAlexander V. Chernikov /* 1338b074b7bbSAlexander V. Chernikov * Tables rewriting code 1339b074b7bbSAlexander V. Chernikov * 1340b074b7bbSAlexander V. Chernikov */ 1341b074b7bbSAlexander V. Chernikov 1342b074b7bbSAlexander V. Chernikov /* 1343b074b7bbSAlexander V. Chernikov * Determine table number and lookup type for @cmd. 1344b074b7bbSAlexander V. Chernikov * Fill @tbl and @type with appropriate values. 1345b074b7bbSAlexander V. Chernikov * Returns 0 for relevant opcodes, 1 otherwise. 1346b074b7bbSAlexander V. Chernikov */ 1347b074b7bbSAlexander V. Chernikov static int 1348b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 1349b074b7bbSAlexander V. Chernikov { 1350b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1351b074b7bbSAlexander V. Chernikov int skip; 1352b074b7bbSAlexander V. Chernikov uint16_t v; 1353b074b7bbSAlexander V. Chernikov 1354b074b7bbSAlexander V. Chernikov skip = 1; 1355b074b7bbSAlexander V. Chernikov 1356b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1357b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1358b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1359b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1360b074b7bbSAlexander V. Chernikov *puidx = cmd->arg1; 1361b074b7bbSAlexander V. Chernikov /* Assume CIDR by default */ 1362b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 1363b074b7bbSAlexander V. Chernikov skip = 0; 1364b074b7bbSAlexander V. Chernikov 1365b074b7bbSAlexander V. Chernikov if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { 1366b074b7bbSAlexander V. Chernikov /* 1367b074b7bbSAlexander V. Chernikov * generic lookup. The key must be 1368b074b7bbSAlexander V. Chernikov * in 32bit big-endian format. 1369b074b7bbSAlexander V. Chernikov */ 1370b074b7bbSAlexander V. Chernikov v = ((ipfw_insn_u32 *)cmd)->d[1]; 1371b074b7bbSAlexander V. Chernikov switch (v) { 1372b074b7bbSAlexander V. Chernikov case 0: 1373b074b7bbSAlexander V. Chernikov case 1: 1374b074b7bbSAlexander V. Chernikov /* IPv4 src/dst */ 1375b074b7bbSAlexander V. Chernikov break; 1376b074b7bbSAlexander V. Chernikov case 2: 1377b074b7bbSAlexander V. Chernikov case 3: 1378b074b7bbSAlexander V. Chernikov /* src/dst port */ 1379b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 1380b074b7bbSAlexander V. Chernikov break; 1381b074b7bbSAlexander V. Chernikov case 4: 1382b074b7bbSAlexander V. Chernikov /* uid/gid */ 1383b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 1384b074b7bbSAlexander V. Chernikov case 5: 1385b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 1386b074b7bbSAlexander V. Chernikov /* jid */ 1387b074b7bbSAlexander V. Chernikov case 6: 1388b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 1389b074b7bbSAlexander V. Chernikov /* dscp */ 1390b074b7bbSAlexander V. Chernikov break; 1391b074b7bbSAlexander V. Chernikov } 1392b074b7bbSAlexander V. Chernikov } 1393b074b7bbSAlexander V. Chernikov break; 1394b074b7bbSAlexander V. Chernikov case O_XMIT: 1395b074b7bbSAlexander V. Chernikov case O_RECV: 1396b074b7bbSAlexander V. Chernikov case O_VIA: 1397b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1398b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1399b074b7bbSAlexander V. Chernikov if (cmdif->name[0] != '\1') 1400b074b7bbSAlexander V. Chernikov break; 1401b074b7bbSAlexander V. Chernikov 1402b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 1403b074b7bbSAlexander V. Chernikov *puidx = cmdif->p.glob; 1404b074b7bbSAlexander V. Chernikov skip = 0; 1405b074b7bbSAlexander V. Chernikov break; 1406b074b7bbSAlexander V. Chernikov } 1407b074b7bbSAlexander V. Chernikov 1408b074b7bbSAlexander V. Chernikov return (skip); 1409b074b7bbSAlexander V. Chernikov } 1410b074b7bbSAlexander V. Chernikov 1411b074b7bbSAlexander V. Chernikov /* 1412b074b7bbSAlexander V. Chernikov * Sets new table value for given opcode. 1413b074b7bbSAlexander V. Chernikov * Assume the same opcodes as classify_table_opcode() 1414b074b7bbSAlexander V. Chernikov */ 1415b074b7bbSAlexander V. Chernikov static void 1416b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx) 1417b074b7bbSAlexander V. Chernikov { 1418b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1419b074b7bbSAlexander V. Chernikov 1420b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1421b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1422b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1423b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1424b074b7bbSAlexander V. Chernikov cmd->arg1 = idx; 1425b074b7bbSAlexander V. Chernikov break; 1426b074b7bbSAlexander V. Chernikov case O_XMIT: 1427b074b7bbSAlexander V. Chernikov case O_RECV: 1428b074b7bbSAlexander V. Chernikov case O_VIA: 1429b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1430b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1431b074b7bbSAlexander V. Chernikov cmdif->p.glob = idx; 1432b074b7bbSAlexander V. Chernikov break; 1433b074b7bbSAlexander V. Chernikov } 1434b074b7bbSAlexander V. Chernikov } 1435b074b7bbSAlexander V. Chernikov 1436ac35ff17SAlexander V. Chernikov /* 1437ac35ff17SAlexander V. Chernikov * Checks table name for validity. 1438ac35ff17SAlexander V. Chernikov * Enforce basic length checks, the rest 1439ac35ff17SAlexander V. Chernikov * should be done in userland. 1440ac35ff17SAlexander V. Chernikov * 1441ac35ff17SAlexander V. Chernikov * Returns 0 if name is considered valid. 1442ac35ff17SAlexander V. Chernikov */ 1443ac35ff17SAlexander V. Chernikov int 1444ac35ff17SAlexander V. Chernikov ipfw_check_table_name(char *name) 1445ac35ff17SAlexander V. Chernikov { 1446ac35ff17SAlexander V. Chernikov int nsize; 1447ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv = NULL; 1448ac35ff17SAlexander V. Chernikov 1449ac35ff17SAlexander V. Chernikov nsize = sizeof(ntlv->name); 1450ac35ff17SAlexander V. Chernikov 1451ac35ff17SAlexander V. Chernikov if (strnlen(name, nsize) == nsize) 1452ac35ff17SAlexander V. Chernikov return (EINVAL); 1453ac35ff17SAlexander V. Chernikov 1454ac35ff17SAlexander V. Chernikov if (name[0] == '\0') 1455ac35ff17SAlexander V. Chernikov return (EINVAL); 1456ac35ff17SAlexander V. Chernikov 1457ac35ff17SAlexander V. Chernikov /* 1458ac35ff17SAlexander V. Chernikov * TODO: do some more complicated checks 1459ac35ff17SAlexander V. Chernikov */ 1460ac35ff17SAlexander V. Chernikov 1461ac35ff17SAlexander V. Chernikov return (0); 1462ac35ff17SAlexander V. Chernikov } 1463ac35ff17SAlexander V. Chernikov 1464ac35ff17SAlexander V. Chernikov /* 1465ac35ff17SAlexander V. Chernikov * Find tablename TLV by @uid. 1466ac35ff17SAlexander V. Chernikov * Check @tlvs for valid data inside. 1467ac35ff17SAlexander V. Chernikov * 1468ac35ff17SAlexander V. Chernikov * Returns pointer to found TLV or NULL. 1469ac35ff17SAlexander V. Chernikov */ 1470ac35ff17SAlexander V. Chernikov static ipfw_obj_ntlv * 1471b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx) 1472b074b7bbSAlexander V. Chernikov { 14739f7d47b0SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1474b074b7bbSAlexander V. Chernikov uintptr_t pa, pe; 1475b074b7bbSAlexander V. Chernikov int l; 1476b074b7bbSAlexander V. Chernikov 1477b074b7bbSAlexander V. Chernikov pa = (uintptr_t)tlvs; 1478b074b7bbSAlexander V. Chernikov pe = pa + len; 1479b074b7bbSAlexander V. Chernikov l = 0; 1480b074b7bbSAlexander V. Chernikov for (; pa < pe; pa += l) { 14819f7d47b0SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)pa; 1482b074b7bbSAlexander V. Chernikov l = ntlv->head.length; 1483ac35ff17SAlexander V. Chernikov 1484ac35ff17SAlexander V. Chernikov if (l != sizeof(*ntlv)) 1485ac35ff17SAlexander V. Chernikov return (NULL); 1486ac35ff17SAlexander V. Chernikov 1487563b5ab1SAlexander V. Chernikov if (ntlv->head.type != IPFW_TLV_TBL_NAME) 1488b074b7bbSAlexander V. Chernikov continue; 1489ac35ff17SAlexander V. Chernikov 1490b074b7bbSAlexander V. Chernikov if (ntlv->idx != uidx) 1491b074b7bbSAlexander V. Chernikov continue; 1492b074b7bbSAlexander V. Chernikov 1493ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(ntlv->name) != 0) 1494ac35ff17SAlexander V. Chernikov return (NULL); 1495ac35ff17SAlexander V. Chernikov 1496ac35ff17SAlexander V. Chernikov return (ntlv); 1497b074b7bbSAlexander V. Chernikov } 1498b074b7bbSAlexander V. Chernikov 1499b074b7bbSAlexander V. Chernikov return (NULL); 1500b074b7bbSAlexander V. Chernikov } 1501b074b7bbSAlexander V. Chernikov 1502ac35ff17SAlexander V. Chernikov /* 1503ac35ff17SAlexander V. Chernikov * Finds table config based on either legacy index 1504ac35ff17SAlexander V. Chernikov * or name in ntlv. 1505ac35ff17SAlexander V. Chernikov * Note @ti structure contains unchecked data from userland. 1506ac35ff17SAlexander V. Chernikov * 1507ac35ff17SAlexander V. Chernikov * Returns pointer to table_config or NULL. 1508ac35ff17SAlexander V. Chernikov */ 1509b074b7bbSAlexander V. Chernikov static struct table_config * 1510b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti) 1511b074b7bbSAlexander V. Chernikov { 1512b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1513b074b7bbSAlexander V. Chernikov struct named_object *no; 1514ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1515ac35ff17SAlexander V. Chernikov uint32_t set; 1516b074b7bbSAlexander V. Chernikov 1517b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1518ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1519ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1520b074b7bbSAlexander V. Chernikov return (NULL); 1521ac35ff17SAlexander V. Chernikov name = ntlv->name; 1522ac35ff17SAlexander V. Chernikov set = ntlv->set; 1523b074b7bbSAlexander V. Chernikov } else { 1524b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1525b074b7bbSAlexander V. Chernikov name = bname; 1526ac35ff17SAlexander V. Chernikov set = 0; 1527b074b7bbSAlexander V. Chernikov } 1528b074b7bbSAlexander V. Chernikov 1529ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_name(ni, set, name); 1530b074b7bbSAlexander V. Chernikov 1531b074b7bbSAlexander V. Chernikov return ((struct table_config *)no); 1532b074b7bbSAlexander V. Chernikov } 1533b074b7bbSAlexander V. Chernikov 1534b074b7bbSAlexander V. Chernikov static struct table_config * 15359f7d47b0SAlexander V. Chernikov alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti, 15369490a627SAlexander V. Chernikov struct table_algo *ta, char *aname) 1537b074b7bbSAlexander V. Chernikov { 1538b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1539b074b7bbSAlexander V. Chernikov struct table_config *tc; 1540b074b7bbSAlexander V. Chernikov int error; 1541ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1542ac35ff17SAlexander V. Chernikov uint32_t set; 1543b074b7bbSAlexander V. Chernikov 1544b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1545ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1546ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1547b074b7bbSAlexander V. Chernikov return (NULL); 1548ac35ff17SAlexander V. Chernikov name = ntlv->name; 1549ac35ff17SAlexander V. Chernikov set = ntlv->set; 1550b074b7bbSAlexander V. Chernikov } else { 1551b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1552b074b7bbSAlexander V. Chernikov name = bname; 1553ac35ff17SAlexander V. Chernikov set = 0; 1554b074b7bbSAlexander V. Chernikov } 1555b074b7bbSAlexander V. Chernikov 1556b074b7bbSAlexander V. Chernikov tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO); 1557b074b7bbSAlexander V. Chernikov tc->no.name = tc->tablename; 1558b074b7bbSAlexander V. Chernikov tc->no.type = ti->type; 1559ac35ff17SAlexander V. Chernikov tc->no.set = set; 15609f7d47b0SAlexander V. Chernikov tc->ta = ta; 1561b074b7bbSAlexander V. Chernikov strlcpy(tc->tablename, name, sizeof(tc->tablename)); 1562ac35ff17SAlexander V. Chernikov /* Set default value type to u32 for compability reasons */ 1563ac35ff17SAlexander V. Chernikov tc->vtype = IPFW_VTYPE_U32; 1564b074b7bbSAlexander V. Chernikov 1565b074b7bbSAlexander V. Chernikov if (ti->tlvs == NULL) { 1566b074b7bbSAlexander V. Chernikov tc->no.compat = 1; 1567b074b7bbSAlexander V. Chernikov tc->no.uidx = ti->uidx; 1568b074b7bbSAlexander V. Chernikov } 1569b074b7bbSAlexander V. Chernikov 1570b074b7bbSAlexander V. Chernikov /* Preallocate data structures for new tables */ 15719490a627SAlexander V. Chernikov error = ta->init(&tc->astate, &tc->ti, aname); 1572b074b7bbSAlexander V. Chernikov if (error != 0) { 1573b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1574b074b7bbSAlexander V. Chernikov return (NULL); 1575b074b7bbSAlexander V. Chernikov } 1576b074b7bbSAlexander V. Chernikov 1577b074b7bbSAlexander V. Chernikov return (tc); 1578b074b7bbSAlexander V. Chernikov } 1579b074b7bbSAlexander V. Chernikov 1580b074b7bbSAlexander V. Chernikov static void 1581b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc) 1582b074b7bbSAlexander V. Chernikov { 1583b074b7bbSAlexander V. Chernikov 1584b074b7bbSAlexander V. Chernikov if (tc->linked == 0) 15859f7d47b0SAlexander V. Chernikov tc->ta->destroy(&tc->astate, &tc->ti); 1586b074b7bbSAlexander V. Chernikov 1587b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1588b074b7bbSAlexander V. Chernikov } 1589b074b7bbSAlexander V. Chernikov 1590b074b7bbSAlexander V. Chernikov /* 1591b074b7bbSAlexander V. Chernikov * Links @tc to @chain table named instance. 1592b074b7bbSAlexander V. Chernikov * Sets appropriate type/states in @chain table info. 1593b074b7bbSAlexander V. Chernikov */ 1594b074b7bbSAlexander V. Chernikov static void 15959f7d47b0SAlexander V. Chernikov link_table(struct ip_fw_chain *ch, struct table_config *tc) 1596b074b7bbSAlexander V. Chernikov { 1597b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 15989f7d47b0SAlexander V. Chernikov struct table_info *ti; 1599b074b7bbSAlexander V. Chernikov uint16_t kidx; 1600b074b7bbSAlexander V. Chernikov 16019f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 16029f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1603b074b7bbSAlexander V. Chernikov 16049f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1605b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1606b074b7bbSAlexander V. Chernikov 1607b074b7bbSAlexander V. Chernikov ipfw_objhash_add(ni, &tc->no); 16089f7d47b0SAlexander V. Chernikov 16099f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 16109f7d47b0SAlexander V. Chernikov *ti = tc->ti; 1611b074b7bbSAlexander V. Chernikov 1612b074b7bbSAlexander V. Chernikov tc->linked = 1; 1613b074b7bbSAlexander V. Chernikov } 1614b074b7bbSAlexander V. Chernikov 1615b074b7bbSAlexander V. Chernikov /* 1616b074b7bbSAlexander V. Chernikov * Unlinks @tc from @chain table named instance. 1617b074b7bbSAlexander V. Chernikov * Zeroes states in @chain and stores them in @tc. 1618b074b7bbSAlexander V. Chernikov */ 1619b074b7bbSAlexander V. Chernikov static void 16209f7d47b0SAlexander V. Chernikov unlink_table(struct ip_fw_chain *ch, struct table_config *tc) 1621b074b7bbSAlexander V. Chernikov { 1622b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 16239f7d47b0SAlexander V. Chernikov struct table_info *ti; 1624b074b7bbSAlexander V. Chernikov uint16_t kidx; 1625b074b7bbSAlexander V. Chernikov 16269f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 16279f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1628b074b7bbSAlexander V. Chernikov 16299f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1630b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1631b074b7bbSAlexander V. Chernikov 16329f7d47b0SAlexander V. Chernikov /* Clear state. @ti copy is already saved inside @tc */ 1633b074b7bbSAlexander V. Chernikov ipfw_objhash_del(ni, &tc->no); 16349f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 16359f7d47b0SAlexander V. Chernikov memset(ti, 0, sizeof(struct table_info)); 1636b074b7bbSAlexander V. Chernikov tc->linked = 0; 1637b074b7bbSAlexander V. Chernikov } 1638b074b7bbSAlexander V. Chernikov 1639b074b7bbSAlexander V. Chernikov /* 1640b074b7bbSAlexander V. Chernikov * Finds named object by @uidx number. 1641b074b7bbSAlexander V. Chernikov * Refs found object, allocate new index for non-existing object. 16429490a627SAlexander V. Chernikov * Fills in @oib with userland/kernel indexes. 16439490a627SAlexander V. Chernikov * First free oidx pointer is saved back in @oib. 1644b074b7bbSAlexander V. Chernikov * 1645b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1646b074b7bbSAlexander V. Chernikov */ 1647b074b7bbSAlexander V. Chernikov static int 16489490a627SAlexander V. Chernikov bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule, 16499490a627SAlexander V. Chernikov struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti) 1650b074b7bbSAlexander V. Chernikov { 1651b074b7bbSAlexander V. Chernikov struct table_config *tc; 16529490a627SAlexander V. Chernikov struct namedobj_instance *ni; 16539490a627SAlexander V. Chernikov struct named_object *no; 16549490a627SAlexander V. Chernikov int error, l, cmdlen; 16559490a627SAlexander V. Chernikov ipfw_insn *cmd; 16569490a627SAlexander V. Chernikov struct obj_idx *pidx, *p; 16579490a627SAlexander V. Chernikov 16589490a627SAlexander V. Chernikov pidx = *oib; 16599490a627SAlexander V. Chernikov l = rule->cmd_len; 16609490a627SAlexander V. Chernikov cmd = rule->cmd; 16619490a627SAlexander V. Chernikov cmdlen = 0; 16629490a627SAlexander V. Chernikov error = 0; 16639490a627SAlexander V. Chernikov 16649490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 16659490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 16669490a627SAlexander V. Chernikov 16679490a627SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 16689490a627SAlexander V. Chernikov cmdlen = F_LEN(cmd); 16699490a627SAlexander V. Chernikov 16709490a627SAlexander V. Chernikov if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0) 16719490a627SAlexander V. Chernikov continue; 1672b074b7bbSAlexander V. Chernikov 1673b074b7bbSAlexander V. Chernikov pidx->uidx = ti->uidx; 1674b074b7bbSAlexander V. Chernikov pidx->type = ti->type; 1675b074b7bbSAlexander V. Chernikov 16769490a627SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 16779490a627SAlexander V. Chernikov if (tc->no.type != ti->type) { 16789490a627SAlexander V. Chernikov /* Incompatible types */ 16799490a627SAlexander V. Chernikov error = EINVAL; 16809490a627SAlexander V. Chernikov break; 16819490a627SAlexander V. Chernikov } 16829f7d47b0SAlexander V. Chernikov 16839490a627SAlexander V. Chernikov /* Reference found table and save kidx */ 16849490a627SAlexander V. Chernikov tc->no.refcnt++; 16859490a627SAlexander V. Chernikov pidx->kidx = tc->no.kidx; 16869490a627SAlexander V. Chernikov pidx++; 16879490a627SAlexander V. Chernikov continue; 16889490a627SAlexander V. Chernikov } 16899490a627SAlexander V. Chernikov 16909490a627SAlexander V. Chernikov /* Table not found. Allocate new index and save for later */ 1691ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &pidx->kidx) != 0) { 1692ac35ff17SAlexander V. Chernikov printf("Unable to allocate table %s index in set %u." 1693b074b7bbSAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 1694ac35ff17SAlexander V. Chernikov "", ti->set); 16959490a627SAlexander V. Chernikov error = EBUSY; 16969490a627SAlexander V. Chernikov break; 1697b074b7bbSAlexander V. Chernikov } 1698b074b7bbSAlexander V. Chernikov 1699b074b7bbSAlexander V. Chernikov ci->new_tables++; 17009490a627SAlexander V. Chernikov pidx->new = 1; 17019490a627SAlexander V. Chernikov pidx++; 1702b074b7bbSAlexander V. Chernikov } 1703b074b7bbSAlexander V. Chernikov 17049490a627SAlexander V. Chernikov if (error != 0) { 17059490a627SAlexander V. Chernikov /* Unref everything we have already done */ 17069490a627SAlexander V. Chernikov for (p = *oib; p < pidx; p++) { 17079490a627SAlexander V. Chernikov if (p->new != 0) { 1708ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, p->kidx); 17099490a627SAlexander V. Chernikov continue; 17109490a627SAlexander V. Chernikov } 1711b074b7bbSAlexander V. Chernikov 17129490a627SAlexander V. Chernikov /* Find & unref by existing idx */ 1713ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, p->kidx); 17149490a627SAlexander V. Chernikov KASSERT(no != NULL, ("Ref'd table %d disappeared", 17159490a627SAlexander V. Chernikov p->kidx)); 1716b074b7bbSAlexander V. Chernikov 17179490a627SAlexander V. Chernikov no->refcnt--; 17189490a627SAlexander V. Chernikov } 17199490a627SAlexander V. Chernikov } 17209490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1721b074b7bbSAlexander V. Chernikov 17229490a627SAlexander V. Chernikov *oib = pidx; 17239490a627SAlexander V. Chernikov 17249490a627SAlexander V. Chernikov return (error); 1725b074b7bbSAlexander V. Chernikov } 1726b074b7bbSAlexander V. Chernikov 1727b074b7bbSAlexander V. Chernikov /* 1728b074b7bbSAlexander V. Chernikov * Compatibility function for old ipfw(8) binaries. 1729b074b7bbSAlexander V. Chernikov * Rewrites table kernel indices with userland ones. 1730b074b7bbSAlexander V. Chernikov * Works for \d+ talbes only (e.g. for tables, converted 1731b074b7bbSAlexander V. Chernikov * from old numbered system calls). 1732b074b7bbSAlexander V. Chernikov * 1733b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1734b074b7bbSAlexander V. Chernikov * Raises error on any other tables. 1735b074b7bbSAlexander V. Chernikov */ 1736b074b7bbSAlexander V. Chernikov int 1737b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule) 1738b074b7bbSAlexander V. Chernikov { 17391832a7b3SAlexander V. Chernikov int cmdlen, error, l; 1740b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 17411832a7b3SAlexander V. Chernikov uint16_t kidx, uidx; 1742b074b7bbSAlexander V. Chernikov uint8_t type; 1743b074b7bbSAlexander V. Chernikov struct named_object *no; 1744b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1745b074b7bbSAlexander V. Chernikov 1746b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 17471832a7b3SAlexander V. Chernikov error = 0; 1748b074b7bbSAlexander V. Chernikov 1749b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1750b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1751b074b7bbSAlexander V. Chernikov cmdlen = 0; 1752b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1753b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1754b074b7bbSAlexander V. Chernikov 1755b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1756b074b7bbSAlexander V. Chernikov continue; 1757b074b7bbSAlexander V. Chernikov 1758ac35ff17SAlexander V. Chernikov if ((no = ipfw_objhash_lookup_kidx(ni, kidx)) == NULL) 1759b074b7bbSAlexander V. Chernikov return (1); 1760b074b7bbSAlexander V. Chernikov 17611832a7b3SAlexander V. Chernikov uidx = no->uidx; 17621832a7b3SAlexander V. Chernikov if (no->compat == 0) { 1763b074b7bbSAlexander V. Chernikov 17641832a7b3SAlexander V. Chernikov /* 17651832a7b3SAlexander V. Chernikov * We are called via legacy opcode. 17661832a7b3SAlexander V. Chernikov * Save error and show table as fake number 17671832a7b3SAlexander V. Chernikov * not to make ipfw(8) hang. 17681832a7b3SAlexander V. Chernikov */ 17691832a7b3SAlexander V. Chernikov uidx = 65535; 17701832a7b3SAlexander V. Chernikov error = 2; 1771b074b7bbSAlexander V. Chernikov } 1772b074b7bbSAlexander V. Chernikov 17731832a7b3SAlexander V. Chernikov update_table_opcode(cmd, uidx); 17741832a7b3SAlexander V. Chernikov } 17751832a7b3SAlexander V. Chernikov 17761832a7b3SAlexander V. Chernikov return (error); 1777b074b7bbSAlexander V. Chernikov } 1778b074b7bbSAlexander V. Chernikov 1779563b5ab1SAlexander V. Chernikov /* 1780563b5ab1SAlexander V. Chernikov * Sets every table kidx in @bmask which is used in rule @rule. 1781563b5ab1SAlexander V. Chernikov * 1782563b5ab1SAlexander V. Chernikov * Returns number of newly-referenced tables. 1783563b5ab1SAlexander V. Chernikov */ 1784563b5ab1SAlexander V. Chernikov int 1785563b5ab1SAlexander V. Chernikov ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule, 1786563b5ab1SAlexander V. Chernikov uint32_t *bmask) 1787563b5ab1SAlexander V. Chernikov { 1788563b5ab1SAlexander V. Chernikov int cmdlen, l, count; 1789563b5ab1SAlexander V. Chernikov ipfw_insn *cmd; 1790563b5ab1SAlexander V. Chernikov uint16_t kidx; 1791563b5ab1SAlexander V. Chernikov uint8_t type; 1792563b5ab1SAlexander V. Chernikov 1793563b5ab1SAlexander V. Chernikov l = rule->cmd_len; 1794563b5ab1SAlexander V. Chernikov cmd = rule->cmd; 1795563b5ab1SAlexander V. Chernikov cmdlen = 0; 1796563b5ab1SAlexander V. Chernikov count = 0; 1797563b5ab1SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1798563b5ab1SAlexander V. Chernikov cmdlen = F_LEN(cmd); 1799563b5ab1SAlexander V. Chernikov 1800563b5ab1SAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1801563b5ab1SAlexander V. Chernikov continue; 1802563b5ab1SAlexander V. Chernikov 1803563b5ab1SAlexander V. Chernikov if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0) 1804563b5ab1SAlexander V. Chernikov count++; 1805563b5ab1SAlexander V. Chernikov 1806563b5ab1SAlexander V. Chernikov bmask[kidx / 32] |= 1 << (kidx % 32); 1807563b5ab1SAlexander V. Chernikov } 1808563b5ab1SAlexander V. Chernikov 1809563b5ab1SAlexander V. Chernikov return (count); 1810563b5ab1SAlexander V. Chernikov } 1811563b5ab1SAlexander V. Chernikov 1812563b5ab1SAlexander V. Chernikov 1813b074b7bbSAlexander V. Chernikov 1814b074b7bbSAlexander V. Chernikov /* 1815b074b7bbSAlexander V. Chernikov * Checks is opcode is referencing table of appropriate type. 1816b074b7bbSAlexander V. Chernikov * Adds reference count for found table if true. 1817b074b7bbSAlexander V. Chernikov * Rewrites user-supplied opcode values with kernel ones. 1818b074b7bbSAlexander V. Chernikov * 1819b074b7bbSAlexander V. Chernikov * Returns 0 on success and appropriate error code otherwise. 1820b074b7bbSAlexander V. Chernikov */ 1821b074b7bbSAlexander V. Chernikov int 1822b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, 1823b074b7bbSAlexander V. Chernikov struct rule_check_info *ci) 1824b074b7bbSAlexander V. Chernikov { 1825b074b7bbSAlexander V. Chernikov int cmdlen, error, ftype, l; 1826b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1827b074b7bbSAlexander V. Chernikov uint16_t uidx; 1828b074b7bbSAlexander V. Chernikov uint8_t type; 1829b074b7bbSAlexander V. Chernikov struct table_config *tc; 18309f7d47b0SAlexander V. Chernikov struct table_algo *ta; 1831b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1832b074b7bbSAlexander V. Chernikov struct named_object *no, *no_n, *no_tmp; 18339490a627SAlexander V. Chernikov struct obj_idx *p, *pidx_first, *pidx_last; 1834b074b7bbSAlexander V. Chernikov struct namedobjects_head nh; 1835b074b7bbSAlexander V. Chernikov struct tid_info ti; 1836b074b7bbSAlexander V. Chernikov 1837b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1838b074b7bbSAlexander V. Chernikov 18399490a627SAlexander V. Chernikov /* Prepare queue to store configs */ 18409490a627SAlexander V. Chernikov TAILQ_INIT(&nh); 18419490a627SAlexander V. Chernikov 1842b074b7bbSAlexander V. Chernikov /* 1843b074b7bbSAlexander V. Chernikov * Prepare an array for storing opcode indices. 1844b074b7bbSAlexander V. Chernikov * Use stack allocation by default. 1845b074b7bbSAlexander V. Chernikov */ 1846b074b7bbSAlexander V. Chernikov if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 1847b074b7bbSAlexander V. Chernikov /* Stack */ 18489490a627SAlexander V. Chernikov pidx_first = ci->obuf; 1849b074b7bbSAlexander V. Chernikov } else 18509490a627SAlexander V. Chernikov pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx), 1851b074b7bbSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1852b074b7bbSAlexander V. Chernikov 18539490a627SAlexander V. Chernikov pidx_last = pidx_first; 1854b074b7bbSAlexander V. Chernikov error = 0; 1855b074b7bbSAlexander V. Chernikov 1856b074b7bbSAlexander V. Chernikov type = 0; 1857b074b7bbSAlexander V. Chernikov ftype = 0; 1858b074b7bbSAlexander V. Chernikov 1859b074b7bbSAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 18601832a7b3SAlexander V. Chernikov 18611832a7b3SAlexander V. Chernikov /* 18621832a7b3SAlexander V. Chernikov * Use default set for looking up tables (old way) or 18631832a7b3SAlexander V. Chernikov * use set rule is assigned to (new way). 18641832a7b3SAlexander V. Chernikov */ 18651832a7b3SAlexander V. Chernikov ti.set = (V_fw_tables_sets != 0) ? ci->krule->set : 0; 18666c2997ffSAlexander V. Chernikov if (ci->ctlv != NULL) { 18676c2997ffSAlexander V. Chernikov ti.tlvs = (void *)(ci->ctlv + 1); 18686c2997ffSAlexander V. Chernikov ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv); 18696c2997ffSAlexander V. Chernikov } 1870b074b7bbSAlexander V. Chernikov 1871b074b7bbSAlexander V. Chernikov /* 18729490a627SAlexander V. Chernikov * Stage 1: reference existing tables, determine number 18739490a627SAlexander V. Chernikov * of tables we need to allocate and allocate indexes for each. 1874b074b7bbSAlexander V. Chernikov */ 18759490a627SAlexander V. Chernikov error = bind_table_rule(chain, ci->krule, ci, &pidx_last, &ti); 1876b074b7bbSAlexander V. Chernikov 1877b074b7bbSAlexander V. Chernikov if (error != 0) { 18789490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 18799490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 1880b074b7bbSAlexander V. Chernikov 1881b074b7bbSAlexander V. Chernikov return (error); 1882b074b7bbSAlexander V. Chernikov } 1883b074b7bbSAlexander V. Chernikov 1884b074b7bbSAlexander V. Chernikov /* 1885b074b7bbSAlexander V. Chernikov * Stage 2: allocate table configs for every non-existent table 1886b074b7bbSAlexander V. Chernikov */ 1887b074b7bbSAlexander V. Chernikov 18889f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 18899490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 1890b074b7bbSAlexander V. Chernikov if (p->new == 0) 1891b074b7bbSAlexander V. Chernikov continue; 1892b074b7bbSAlexander V. Chernikov 1893b074b7bbSAlexander V. Chernikov ti.uidx = p->uidx; 1894b074b7bbSAlexander V. Chernikov ti.type = p->type; 18959f7d47b0SAlexander V. Chernikov ti.atype = 0; 1896b074b7bbSAlexander V. Chernikov 18979490a627SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti, NULL); 18989f7d47b0SAlexander V. Chernikov if (ta == NULL) { 18999f7d47b0SAlexander V. Chernikov error = ENOTSUP; 19009f7d47b0SAlexander V. Chernikov goto free; 19019f7d47b0SAlexander V. Chernikov } 19029490a627SAlexander V. Chernikov tc = alloc_table_config(ni, &ti, ta, NULL); 1903b074b7bbSAlexander V. Chernikov 1904b074b7bbSAlexander V. Chernikov if (tc == NULL) { 1905b074b7bbSAlexander V. Chernikov error = ENOMEM; 1906b074b7bbSAlexander V. Chernikov goto free; 1907b074b7bbSAlexander V. Chernikov } 1908b074b7bbSAlexander V. Chernikov 1909b074b7bbSAlexander V. Chernikov tc->no.kidx = p->kidx; 1910b074b7bbSAlexander V. Chernikov tc->no.refcnt = 1; 1911b074b7bbSAlexander V. Chernikov 1912b074b7bbSAlexander V. Chernikov /* Add to list */ 1913b074b7bbSAlexander V. Chernikov TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next); 1914b074b7bbSAlexander V. Chernikov } 1915b074b7bbSAlexander V. Chernikov 1916b074b7bbSAlexander V. Chernikov /* 1917b074b7bbSAlexander V. Chernikov * Stage 2.1: Check if we're going to create 2 tables 1918b074b7bbSAlexander V. Chernikov * with the same name, but different table types. 1919b074b7bbSAlexander V. Chernikov */ 1920b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no, &nh, nn_next) { 1921b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no_tmp, &nh, nn_next) { 19229490a627SAlexander V. Chernikov if (ipfw_objhash_same_name(ni, no, no_tmp) == 0) 1923b074b7bbSAlexander V. Chernikov continue; 1924b074b7bbSAlexander V. Chernikov if (no->type != no_tmp->type) { 1925b074b7bbSAlexander V. Chernikov error = EINVAL; 1926b074b7bbSAlexander V. Chernikov goto free; 1927b074b7bbSAlexander V. Chernikov } 1928b074b7bbSAlexander V. Chernikov } 1929b074b7bbSAlexander V. Chernikov } 19309f7d47b0SAlexander V. Chernikov } 1931b074b7bbSAlexander V. Chernikov 19329f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 19339f7d47b0SAlexander V. Chernikov 19349f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 1935b074b7bbSAlexander V. Chernikov /* 1936b074b7bbSAlexander V. Chernikov * Stage 3: link & reference new table configs 1937b074b7bbSAlexander V. Chernikov */ 1938b074b7bbSAlexander V. Chernikov 1939b074b7bbSAlexander V. Chernikov 1940b074b7bbSAlexander V. Chernikov /* 1941b074b7bbSAlexander V. Chernikov * Step 3.1: Check if some tables we need to create have been 1942b074b7bbSAlexander V. Chernikov * already created with different table type. 1943b074b7bbSAlexander V. Chernikov */ 1944b074b7bbSAlexander V. Chernikov 1945b074b7bbSAlexander V. Chernikov error = 0; 1946b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1947b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1948b074b7bbSAlexander V. Chernikov if (no_n == NULL) 1949b074b7bbSAlexander V. Chernikov continue; 1950b074b7bbSAlexander V. Chernikov 1951b074b7bbSAlexander V. Chernikov if (no_n->type != no->type) { 1952b074b7bbSAlexander V. Chernikov error = EINVAL; 1953b074b7bbSAlexander V. Chernikov break; 1954b074b7bbSAlexander V. Chernikov } 1955b074b7bbSAlexander V. Chernikov 1956b074b7bbSAlexander V. Chernikov } 1957b074b7bbSAlexander V. Chernikov 1958b074b7bbSAlexander V. Chernikov if (error != 0) { 1959b074b7bbSAlexander V. Chernikov /* 1960b074b7bbSAlexander V. Chernikov * Someone has allocated table with different table type. 1961b074b7bbSAlexander V. Chernikov * We have to rollback everything. 1962b074b7bbSAlexander V. Chernikov */ 1963b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1964b074b7bbSAlexander V. Chernikov goto free; 1965b074b7bbSAlexander V. Chernikov } 1966b074b7bbSAlexander V. Chernikov 1967b074b7bbSAlexander V. Chernikov /* 19689f7d47b0SAlexander V. Chernikov * Attach new tables. 19699f7d47b0SAlexander V. Chernikov * We need to set table pointers for each new table, 1970b074b7bbSAlexander V. Chernikov * so we have to acquire main WLOCK. 1971b074b7bbSAlexander V. Chernikov */ 1972b074b7bbSAlexander V. Chernikov IPFW_WLOCK(chain); 1973b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1974b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1975b074b7bbSAlexander V. Chernikov 19769490a627SAlexander V. Chernikov if (no_n == NULL) { 19779490a627SAlexander V. Chernikov /* New table. Attach to runtime hash */ 19789490a627SAlexander V. Chernikov TAILQ_REMOVE(&nh, no, nn_next); 19799490a627SAlexander V. Chernikov link_table(chain, (struct table_config *)no); 1980b074b7bbSAlexander V. Chernikov continue; 1981b074b7bbSAlexander V. Chernikov } 1982b074b7bbSAlexander V. Chernikov 19839490a627SAlexander V. Chernikov /* 19849490a627SAlexander V. Chernikov * Newly-allocated table with the same type. 19859490a627SAlexander V. Chernikov * Reference it and update out @pidx array 19869490a627SAlexander V. Chernikov * rewrite info. 19879490a627SAlexander V. Chernikov */ 19889490a627SAlexander V. Chernikov no_n->refcnt++; 19899490a627SAlexander V. Chernikov /* Keep oib array in sync: update kidx */ 19909490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 19919490a627SAlexander V. Chernikov if (p->kidx != no->kidx) 19929490a627SAlexander V. Chernikov continue; 19939490a627SAlexander V. Chernikov /* Update kidx */ 19949490a627SAlexander V. Chernikov p->kidx = no_n->kidx; 19959490a627SAlexander V. Chernikov break; 19969490a627SAlexander V. Chernikov } 1997b074b7bbSAlexander V. Chernikov } 1998b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(chain); 19999f7d47b0SAlexander V. Chernikov } 2000b074b7bbSAlexander V. Chernikov 2001b074b7bbSAlexander V. Chernikov /* Perform rule rewrite */ 2002b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 2003b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 2004b074b7bbSAlexander V. Chernikov cmdlen = 0; 20059490a627SAlexander V. Chernikov p = pidx_first; 2006b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2007b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2008b074b7bbSAlexander V. Chernikov 2009b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &uidx, &type) != 0) 2010b074b7bbSAlexander V. Chernikov continue; 20119490a627SAlexander V. Chernikov update_table_opcode(cmd, p->kidx); 20129490a627SAlexander V. Chernikov p++; 2013b074b7bbSAlexander V. Chernikov } 2014b074b7bbSAlexander V. Chernikov 2015b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 2016b074b7bbSAlexander V. Chernikov 2017b074b7bbSAlexander V. Chernikov error = 0; 2018b074b7bbSAlexander V. Chernikov 2019b074b7bbSAlexander V. Chernikov /* 2020b074b7bbSAlexander V. Chernikov * Stage 4: free resources 2021b074b7bbSAlexander V. Chernikov */ 2022b074b7bbSAlexander V. Chernikov free: 20239490a627SAlexander V. Chernikov if (!TAILQ_EMPTY(&nh)) { 20249490a627SAlexander V. Chernikov /* Free indexes first */ 20259490a627SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 20269490a627SAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2027ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, no->kidx); 20289490a627SAlexander V. Chernikov } 20299490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 20309490a627SAlexander V. Chernikov /* Free configs */ 2031b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) 2032b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 20339490a627SAlexander V. Chernikov } 2034b074b7bbSAlexander V. Chernikov 20359490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 20369490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 2037b074b7bbSAlexander V. Chernikov 2038b074b7bbSAlexander V. Chernikov return (error); 2039b074b7bbSAlexander V. Chernikov } 2040b074b7bbSAlexander V. Chernikov 2041b074b7bbSAlexander V. Chernikov /* 2042b074b7bbSAlexander V. Chernikov * Remove references from every table used in @rule. 2043b074b7bbSAlexander V. Chernikov */ 2044b074b7bbSAlexander V. Chernikov void 2045b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule) 2046b074b7bbSAlexander V. Chernikov { 2047b074b7bbSAlexander V. Chernikov int cmdlen, l; 2048b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 2049b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2050b074b7bbSAlexander V. Chernikov struct named_object *no; 2051b074b7bbSAlexander V. Chernikov uint16_t kidx; 2052b074b7bbSAlexander V. Chernikov uint8_t type; 2053b074b7bbSAlexander V. Chernikov 2054b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 2055b074b7bbSAlexander V. Chernikov 2056b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 2057b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 2058b074b7bbSAlexander V. Chernikov cmdlen = 0; 2059b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2060b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2061b074b7bbSAlexander V. Chernikov 2062b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2063b074b7bbSAlexander V. Chernikov continue; 2064b074b7bbSAlexander V. Chernikov 2065ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 2066b074b7bbSAlexander V. Chernikov 2067b074b7bbSAlexander V. Chernikov KASSERT(no != NULL, ("table id %d not found", kidx)); 2068b074b7bbSAlexander V. Chernikov KASSERT(no->type == type, ("wrong type %d (%d) for table id %d", 2069b074b7bbSAlexander V. Chernikov no->type, type, kidx)); 2070b074b7bbSAlexander V. Chernikov KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 2071b074b7bbSAlexander V. Chernikov kidx, no->refcnt)); 2072b074b7bbSAlexander V. Chernikov 2073b074b7bbSAlexander V. Chernikov no->refcnt--; 2074b074b7bbSAlexander V. Chernikov } 2075b074b7bbSAlexander V. Chernikov } 2076b074b7bbSAlexander V. Chernikov 2077b074b7bbSAlexander V. Chernikov 2078b074b7bbSAlexander V. Chernikov /* 2079b074b7bbSAlexander V. Chernikov * Removes table bindings for every rule in rule chain @head. 2080b074b7bbSAlexander V. Chernikov */ 2081b074b7bbSAlexander V. Chernikov void 2082b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head) 2083b074b7bbSAlexander V. Chernikov { 2084b074b7bbSAlexander V. Chernikov struct ip_fw *rule; 2085b074b7bbSAlexander V. Chernikov 2086b074b7bbSAlexander V. Chernikov while ((rule = head) != NULL) { 2087b074b7bbSAlexander V. Chernikov head = head->x_next; 2088b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(chain, rule); 2089b074b7bbSAlexander V. Chernikov } 2090b074b7bbSAlexander V. Chernikov } 2091b074b7bbSAlexander V. Chernikov 2092b074b7bbSAlexander V. Chernikov 20933b3a8eb9SGleb Smirnoff /* end of file */ 2094