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 * 32563b5ab1SAlexander V. Chernikov * This file containg 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; 78b074b7bbSAlexander V. Chernikov uint8_t ftype; /* 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); 106f1220db8SAlexander V. Chernikov static void export_table_info(struct table_config *tc, ipfw_xtable_info *i); 107f1220db8SAlexander V. Chernikov static int dump_table_xentry(void *e, void *arg); 108b074b7bbSAlexander V. Chernikov 1092d99a349SAlexander V. Chernikov static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd); 1102d99a349SAlexander V. Chernikov static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd); 111d3a4f924SAlexander V. Chernikov 1129f7d47b0SAlexander V. Chernikov static struct table_algo *find_table_algo(struct tables_config *tableconf, 1139490a627SAlexander V. Chernikov struct tid_info *ti, char *name); 114b074b7bbSAlexander V. Chernikov 115b074b7bbSAlexander V. Chernikov #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) 116b074b7bbSAlexander V. Chernikov #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) 1179f7d47b0SAlexander V. Chernikov #define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) 118b074b7bbSAlexander V. Chernikov 119b074b7bbSAlexander V. Chernikov 1203b3a8eb9SGleb Smirnoff 1213b3a8eb9SGleb Smirnoff int 122b074b7bbSAlexander V. Chernikov ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 123b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 1243b3a8eb9SGleb Smirnoff { 125b074b7bbSAlexander V. Chernikov struct table_config *tc, *tc_new; 1269f7d47b0SAlexander V. Chernikov struct table_algo *ta; 127b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 128b074b7bbSAlexander V. Chernikov uint16_t kidx; 1299f7d47b0SAlexander V. Chernikov int error; 1309f7d47b0SAlexander V. Chernikov char ta_buf[128]; 1313b3a8eb9SGleb Smirnoff 1329f7d47b0SAlexander V. Chernikov #if 0 133b074b7bbSAlexander V. Chernikov if (ti->uidx >= V_fw_tables_max) 1343b3a8eb9SGleb Smirnoff return (EINVAL); 1353b3a8eb9SGleb Smirnoff #endif 1369f7d47b0SAlexander V. Chernikov 1379f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1389f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1399f7d47b0SAlexander V. Chernikov 1409f7d47b0SAlexander V. Chernikov /* 1419f7d47b0SAlexander V. Chernikov * Find and reference existing table. 1429f7d47b0SAlexander V. Chernikov */ 1439f7d47b0SAlexander V. Chernikov ta = NULL; 1449f7d47b0SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1459f7d47b0SAlexander V. Chernikov /* check table type */ 1469f7d47b0SAlexander V. Chernikov if (tc->no.type != ti->type) { 1479f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1483b3a8eb9SGleb Smirnoff return (EINVAL); 1493b3a8eb9SGleb Smirnoff } 1503b3a8eb9SGleb Smirnoff 1519f7d47b0SAlexander V. Chernikov /* Reference and unlock */ 1529f7d47b0SAlexander V. Chernikov tc->no.refcnt++; 1539f7d47b0SAlexander V. Chernikov ta = tc->ta; 1549f7d47b0SAlexander V. Chernikov } 1559f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1563b3a8eb9SGleb Smirnoff 1579f7d47b0SAlexander V. Chernikov tc_new = NULL; 1589f7d47b0SAlexander V. Chernikov if (ta == NULL) { 1599f7d47b0SAlexander V. Chernikov /* Table not found. We have to create new one */ 1609490a627SAlexander V. Chernikov if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, NULL)) == NULL) 1619f7d47b0SAlexander V. Chernikov return (ENOTSUP); 1623b3a8eb9SGleb Smirnoff 1639490a627SAlexander V. Chernikov tc_new = alloc_table_config(ni, ti, ta, NULL); 1649f7d47b0SAlexander V. Chernikov if (tc_new == NULL) 1659f7d47b0SAlexander V. Chernikov return (ENOMEM); 1669f7d47b0SAlexander V. Chernikov } 1673b3a8eb9SGleb Smirnoff 1689f7d47b0SAlexander V. Chernikov /* Prepare record (allocate memory) */ 1699f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 1709f7d47b0SAlexander V. Chernikov error = ta->prepare_add(tei, &ta_buf); 1719f7d47b0SAlexander V. Chernikov if (error != 0) { 1729f7d47b0SAlexander V. Chernikov if (tc_new != NULL) 1739f7d47b0SAlexander V. Chernikov free_table_config(ni, tc_new); 1749f7d47b0SAlexander V. Chernikov return (error); 1753b3a8eb9SGleb Smirnoff } 1763b3a8eb9SGleb Smirnoff 177b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1783b3a8eb9SGleb Smirnoff 179b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1803b3a8eb9SGleb Smirnoff 1819f7d47b0SAlexander V. Chernikov if (tc == NULL) { 1829f7d47b0SAlexander V. Chernikov /* Check if another table was allocated by other thread */ 183b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1849f7d47b0SAlexander V. Chernikov 1859f7d47b0SAlexander V. Chernikov /* 1869f7d47b0SAlexander V. Chernikov * Check if algoritm is the same since we've 1879f7d47b0SAlexander V. Chernikov * already allocated state using @ta algoritm 1889f7d47b0SAlexander V. Chernikov * callbacks. 1899f7d47b0SAlexander V. Chernikov */ 1909f7d47b0SAlexander V. Chernikov if (tc->ta != ta) { 191b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 192b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 1933b3a8eb9SGleb Smirnoff return (EINVAL); 1943b3a8eb9SGleb Smirnoff } 1953b3a8eb9SGleb Smirnoff } else { 1963b3a8eb9SGleb Smirnoff /* 1979f7d47b0SAlexander V. Chernikov * We're first to create this table. 198b074b7bbSAlexander V. Chernikov * Set tc_new to zero not to free it afterwards. 1993b3a8eb9SGleb Smirnoff */ 200b074b7bbSAlexander V. Chernikov tc = tc_new; 201b074b7bbSAlexander V. Chernikov tc_new = NULL; 202b074b7bbSAlexander V. Chernikov 203b074b7bbSAlexander V. Chernikov /* Allocate table index. */ 204b074b7bbSAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, ti->set, &kidx) != 0) { 205b074b7bbSAlexander V. Chernikov /* Index full. */ 206b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 207b074b7bbSAlexander V. Chernikov printf("Unable to allocate index for table %s." 208b074b7bbSAlexander V. Chernikov " Consider increasing " 209b074b7bbSAlexander V. Chernikov "net.inet.ip.fw.tables_max", 210b074b7bbSAlexander V. Chernikov tc->no.name); 211b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 212b074b7bbSAlexander V. Chernikov return (EBUSY); 2133b3a8eb9SGleb Smirnoff } 214b074b7bbSAlexander V. Chernikov /* Save kidx */ 215b074b7bbSAlexander V. Chernikov tc->no.kidx = kidx; 216b074b7bbSAlexander V. Chernikov } 217b074b7bbSAlexander V. Chernikov } else { 2189f7d47b0SAlexander V. Chernikov /* Drop reference we've used in first search */ 2199f7d47b0SAlexander V. Chernikov tc->no.refcnt--; 220b074b7bbSAlexander V. Chernikov } 221b074b7bbSAlexander V. Chernikov 222b074b7bbSAlexander V. Chernikov /* We've got valid table in @tc. Let's add data */ 2239f7d47b0SAlexander V. Chernikov kidx = tc->no.kidx; 2249f7d47b0SAlexander V. Chernikov ta = tc->ta; 2259f7d47b0SAlexander V. Chernikov 226b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 227b074b7bbSAlexander V. Chernikov 228b074b7bbSAlexander V. Chernikov if (tc->linked == 0) { 229b074b7bbSAlexander V. Chernikov link_table(ch, tc); 230b074b7bbSAlexander V. Chernikov } 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 2369f7d47b0SAlexander V. Chernikov if (error == 0) 2379f7d47b0SAlexander V. Chernikov tc->count++; 2389f7d47b0SAlexander V. Chernikov 239b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 240b074b7bbSAlexander V. Chernikov 241b074b7bbSAlexander V. Chernikov if (tc_new != NULL) 242b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 2433b3a8eb9SGleb Smirnoff 2449f7d47b0SAlexander V. Chernikov if (error != 0) 2459f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 246b074b7bbSAlexander V. Chernikov 2479f7d47b0SAlexander V. Chernikov return (error); 2483b3a8eb9SGleb Smirnoff } 2493b3a8eb9SGleb Smirnoff 2503b3a8eb9SGleb Smirnoff int 251b074b7bbSAlexander V. Chernikov ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 252b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 2533b3a8eb9SGleb Smirnoff { 254b074b7bbSAlexander V. Chernikov struct table_config *tc; 2559f7d47b0SAlexander V. Chernikov struct table_algo *ta; 256b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 257b074b7bbSAlexander V. Chernikov uint16_t kidx; 2589f7d47b0SAlexander V. Chernikov int error; 2599f7d47b0SAlexander V. Chernikov char ta_buf[128]; 2603b3a8eb9SGleb Smirnoff 2619f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 262b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 263b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 2649f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2653b3a8eb9SGleb Smirnoff return (ESRCH); 2663b3a8eb9SGleb Smirnoff } 2673b3a8eb9SGleb Smirnoff 268b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 2699f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2703b3a8eb9SGleb Smirnoff return (EINVAL); 2713b3a8eb9SGleb Smirnoff } 2729f7d47b0SAlexander V. Chernikov 2739f7d47b0SAlexander V. Chernikov ta = tc->ta; 2749f7d47b0SAlexander V. Chernikov 2759f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 2769f7d47b0SAlexander V. Chernikov if ((error = ta->prepare_del(tei, &ta_buf)) != 0) { 2779f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2789f7d47b0SAlexander V. Chernikov return (error); 2799f7d47b0SAlexander V. Chernikov } 2809f7d47b0SAlexander V. Chernikov 281b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 282b074b7bbSAlexander V. Chernikov 283b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 2849f7d47b0SAlexander V. Chernikov error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); 2853b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2863b3a8eb9SGleb Smirnoff 2879f7d47b0SAlexander V. Chernikov if (error == 0) 2889f7d47b0SAlexander V. Chernikov tc->count--; 289b074b7bbSAlexander V. Chernikov 2909f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2913b3a8eb9SGleb Smirnoff 2929f7d47b0SAlexander V. Chernikov if (error != 0) 2939f7d47b0SAlexander V. Chernikov return (error); 2943b3a8eb9SGleb Smirnoff 2959f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 2963b3a8eb9SGleb Smirnoff return (0); 2973b3a8eb9SGleb Smirnoff } 2983b3a8eb9SGleb Smirnoff 299b074b7bbSAlexander V. Chernikov /* 3009f7d47b0SAlexander V. Chernikov * Flushes all entries in given table. 301b074b7bbSAlexander V. Chernikov */ 3023b3a8eb9SGleb Smirnoff int 303b074b7bbSAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti) 3043b3a8eb9SGleb Smirnoff { 305b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 306b074b7bbSAlexander V. Chernikov struct table_config *tc; 3079f7d47b0SAlexander V. Chernikov struct table_algo *ta; 3089f7d47b0SAlexander V. Chernikov struct table_info ti_old, ti_new, *tablestate; 3099f7d47b0SAlexander V. Chernikov void *astate_old, *astate_new; 310b074b7bbSAlexander V. Chernikov int error; 311b074b7bbSAlexander V. Chernikov uint16_t kidx; 3123b3a8eb9SGleb Smirnoff 3133b3a8eb9SGleb Smirnoff /* 3149f7d47b0SAlexander V. Chernikov * Stage 1: save table algoritm. 315b074b7bbSAlexander V. Chernikov * Reference found table to ensure it won't disappear. 3163b3a8eb9SGleb Smirnoff */ 317b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 318b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 319b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 320b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 321b074b7bbSAlexander V. Chernikov return (ESRCH); 322b074b7bbSAlexander V. Chernikov } 3239f7d47b0SAlexander V. Chernikov ta = tc->ta; 324b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 325b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3263b3a8eb9SGleb Smirnoff 327b074b7bbSAlexander V. Chernikov /* 3289f7d47b0SAlexander V. Chernikov * Stage 2: allocate new table instance using same algo. 3299490a627SAlexander V. Chernikov * TODO: pass startup parametes somehow. 330b074b7bbSAlexander V. Chernikov */ 3319f7d47b0SAlexander V. Chernikov memset(&ti_new, 0, sizeof(struct table_info)); 3329490a627SAlexander V. Chernikov if ((error = ta->init(&astate_new, &ti_new, NULL)) != 0) { 333b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 334b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 335b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 336b074b7bbSAlexander V. Chernikov return (error); 337b074b7bbSAlexander V. Chernikov } 338b074b7bbSAlexander V. Chernikov 339b074b7bbSAlexander V. Chernikov /* 340b074b7bbSAlexander V. Chernikov * Stage 3: swap old state pointers with newly-allocated ones. 341b074b7bbSAlexander V. Chernikov * Decrease refcount. 342b074b7bbSAlexander V. Chernikov */ 343b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 344b074b7bbSAlexander V. Chernikov 345b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 346b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 3479f7d47b0SAlexander V. Chernikov tablestate = (struct table_info *)ch->tablestate; 348b074b7bbSAlexander V. Chernikov 3499f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 3509f7d47b0SAlexander V. Chernikov ti_old = tablestate[kidx]; 3519f7d47b0SAlexander V. Chernikov tablestate[kidx] = ti_new; 3529f7d47b0SAlexander V. Chernikov IPFW_WUNLOCK(ch); 353b074b7bbSAlexander V. Chernikov 3549f7d47b0SAlexander V. Chernikov astate_old = tc->astate; 3559f7d47b0SAlexander V. Chernikov tc->astate = astate_new; 3569f7d47b0SAlexander V. Chernikov tc->ti = ti_new; 3579f7d47b0SAlexander V. Chernikov tc->count = 0; 358b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 359b074b7bbSAlexander V. Chernikov 360b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3613b3a8eb9SGleb Smirnoff 362b074b7bbSAlexander V. Chernikov /* 363b074b7bbSAlexander V. Chernikov * Stage 4: perform real flush. 364b074b7bbSAlexander V. Chernikov */ 3659f7d47b0SAlexander V. Chernikov ta->destroy(astate_old, &ti_old); 3663b3a8eb9SGleb Smirnoff 3673b3a8eb9SGleb Smirnoff return (0); 3683b3a8eb9SGleb Smirnoff } 3693b3a8eb9SGleb Smirnoff 370b074b7bbSAlexander V. Chernikov /* 3719f7d47b0SAlexander V. Chernikov * Destroys table specified by @ti. 372b074b7bbSAlexander V. Chernikov */ 373b074b7bbSAlexander V. Chernikov int 3749f7d47b0SAlexander V. Chernikov ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) 375b074b7bbSAlexander V. Chernikov { 376b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 377b074b7bbSAlexander V. Chernikov struct table_config *tc; 378b074b7bbSAlexander V. Chernikov 379b074b7bbSAlexander V. Chernikov ti->set = TABLE_SET(ti->set); 380b074b7bbSAlexander V. Chernikov 381b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 382b074b7bbSAlexander V. Chernikov 383b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 384b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 385b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 386b074b7bbSAlexander V. Chernikov return (ESRCH); 387b074b7bbSAlexander V. Chernikov } 388b074b7bbSAlexander V. Chernikov 3899f7d47b0SAlexander V. Chernikov /* Do not permit destroying referenced tables */ 3909f7d47b0SAlexander V. Chernikov if (tc->no.refcnt > 0) { 391b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 392b074b7bbSAlexander V. Chernikov return (EBUSY); 393b074b7bbSAlexander V. Chernikov } 394b074b7bbSAlexander V. Chernikov 395b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 396b074b7bbSAlexander V. Chernikov unlink_table(ch, tc); 397b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 398b074b7bbSAlexander V. Chernikov 399b074b7bbSAlexander V. Chernikov /* Free obj index */ 400b074b7bbSAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, tc->no.set, tc->no.kidx) != 0) 401b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 402b074b7bbSAlexander V. Chernikov tc->no.kidx, tc->tablename); 403b074b7bbSAlexander V. Chernikov 404b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 405b074b7bbSAlexander V. Chernikov 406b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 407b074b7bbSAlexander V. Chernikov 408b074b7bbSAlexander V. Chernikov return (0); 409b074b7bbSAlexander V. Chernikov } 410b074b7bbSAlexander V. Chernikov 411b074b7bbSAlexander V. Chernikov static void 412b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, 413b074b7bbSAlexander V. Chernikov void *arg) 414b074b7bbSAlexander V. Chernikov { 415b074b7bbSAlexander V. Chernikov 416b074b7bbSAlexander V. Chernikov unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); 417b074b7bbSAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, no->set, no->kidx) != 0) 418b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 419b074b7bbSAlexander V. Chernikov no->kidx, no->name); 420b074b7bbSAlexander V. Chernikov free_table_config(ni, (struct table_config *)no); 421b074b7bbSAlexander V. Chernikov } 422b074b7bbSAlexander V. Chernikov 4233b3a8eb9SGleb Smirnoff void 4243b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch) 4253b3a8eb9SGleb Smirnoff { 4263b3a8eb9SGleb Smirnoff 427b074b7bbSAlexander V. Chernikov /* Remove all tables from working set */ 428b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 429b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 430b074b7bbSAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); 431b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 432b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 4333b3a8eb9SGleb Smirnoff 4343b3a8eb9SGleb Smirnoff /* Free pointers itself */ 4359f7d47b0SAlexander V. Chernikov free(ch->tablestate, M_IPFW); 4369f7d47b0SAlexander V. Chernikov 4379f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(ch); 438b074b7bbSAlexander V. Chernikov 439b074b7bbSAlexander V. Chernikov ipfw_objhash_destroy(CHAIN_TO_NI(ch)); 440b074b7bbSAlexander V. Chernikov free(CHAIN_TO_TCFG(ch), M_IPFW); 4413b3a8eb9SGleb Smirnoff } 4423b3a8eb9SGleb Smirnoff 4433b3a8eb9SGleb Smirnoff int 4443b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch) 4453b3a8eb9SGleb Smirnoff { 446b074b7bbSAlexander V. Chernikov struct tables_config *tcfg; 447b074b7bbSAlexander V. Chernikov 4483b3a8eb9SGleb Smirnoff /* Allocate pointers */ 4499f7d47b0SAlexander V. Chernikov ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), 4509f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 451b074b7bbSAlexander V. Chernikov 452b074b7bbSAlexander V. Chernikov tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); 453b074b7bbSAlexander V. Chernikov tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); 454b074b7bbSAlexander V. Chernikov ch->tblcfg = tcfg; 455b074b7bbSAlexander V. Chernikov 4569f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(ch); 4579f7d47b0SAlexander V. Chernikov 4583b3a8eb9SGleb Smirnoff return (0); 4593b3a8eb9SGleb Smirnoff } 4603b3a8eb9SGleb Smirnoff 4613b3a8eb9SGleb Smirnoff int 4623b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) 4633b3a8eb9SGleb Smirnoff { 4643b3a8eb9SGleb Smirnoff unsigned int ntables_old, tbl; 465b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 4669f7d47b0SAlexander V. Chernikov void *new_idx, *old_tablestate, *tablestate; 467b074b7bbSAlexander V. Chernikov int new_blocks; 4683b3a8eb9SGleb Smirnoff 4693b3a8eb9SGleb Smirnoff /* Check new value for validity */ 4703b3a8eb9SGleb Smirnoff if (ntables > IPFW_TABLES_MAX) 4713b3a8eb9SGleb Smirnoff ntables = IPFW_TABLES_MAX; 4723b3a8eb9SGleb Smirnoff 4733b3a8eb9SGleb Smirnoff /* Allocate new pointers */ 4749f7d47b0SAlexander V. Chernikov tablestate = malloc(ntables * sizeof(struct table_info), 4759f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 4769f7d47b0SAlexander V. Chernikov 477b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); 4783b3a8eb9SGleb Smirnoff 4799f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 4803b3a8eb9SGleb Smirnoff 4813b3a8eb9SGleb Smirnoff tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables; 482b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 483b074b7bbSAlexander V. Chernikov 4849f7d47b0SAlexander V. Chernikov /* Temporary restrict decreasing max_tables */ 4859f7d47b0SAlexander V. Chernikov if (ntables < V_fw_tables_max) { 4869f7d47b0SAlexander V. Chernikov 4879f7d47b0SAlexander V. Chernikov /* 4889f7d47b0SAlexander V. Chernikov * FIXME: Check if we really can shrink 4899f7d47b0SAlexander V. Chernikov */ 4909f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 491b074b7bbSAlexander V. Chernikov return (EINVAL); 492b074b7bbSAlexander V. Chernikov } 4933b3a8eb9SGleb Smirnoff 4949f7d47b0SAlexander V. Chernikov /* Copy table info/indices */ 4959f7d47b0SAlexander V. Chernikov memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl); 4969f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks); 4973b3a8eb9SGleb Smirnoff 4989f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 4999f7d47b0SAlexander V. Chernikov 5009f7d47b0SAlexander V. Chernikov /* Change pointers */ 5019f7d47b0SAlexander V. Chernikov old_tablestate = ch->tablestate; 5029f7d47b0SAlexander V. Chernikov ch->tablestate = tablestate; 5039f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks); 5043b3a8eb9SGleb Smirnoff 5053b3a8eb9SGleb Smirnoff ntables_old = V_fw_tables_max; 5063b3a8eb9SGleb Smirnoff V_fw_tables_max = ntables; 5073b3a8eb9SGleb Smirnoff 5083b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 5099f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 5103b3a8eb9SGleb Smirnoff 5113b3a8eb9SGleb Smirnoff /* Free old pointers */ 5129f7d47b0SAlexander V. Chernikov free(old_tablestate, M_IPFW); 513b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 5143b3a8eb9SGleb Smirnoff 5153b3a8eb9SGleb Smirnoff return (0); 5163b3a8eb9SGleb Smirnoff } 5173b3a8eb9SGleb Smirnoff 5183b3a8eb9SGleb Smirnoff int 5193b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 5203b3a8eb9SGleb Smirnoff uint32_t *val) 5213b3a8eb9SGleb Smirnoff { 5229f7d47b0SAlexander V. Chernikov struct table_info *ti; 5233b3a8eb9SGleb Smirnoff 5249f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 5259f7d47b0SAlexander V. Chernikov 5269f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, &addr, sizeof(in_addr_t), val)); 5273b3a8eb9SGleb Smirnoff } 5289f7d47b0SAlexander V. Chernikov 5299f7d47b0SAlexander V. Chernikov int 5309f7d47b0SAlexander V. Chernikov ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, 5319f7d47b0SAlexander V. Chernikov void *paddr, uint32_t *val) 5329f7d47b0SAlexander V. Chernikov { 5339f7d47b0SAlexander V. Chernikov struct table_info *ti; 5349f7d47b0SAlexander V. Chernikov 5359f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 5369f7d47b0SAlexander V. Chernikov 5379f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, paddr, plen, val)); 5389f7d47b0SAlexander V. Chernikov } 5399f7d47b0SAlexander V. Chernikov 5409f7d47b0SAlexander V. Chernikov /* 5419f7d47b0SAlexander V. Chernikov * Info/List/dump support for tables. 5429f7d47b0SAlexander V. Chernikov * 5439f7d47b0SAlexander V. Chernikov */ 5449f7d47b0SAlexander V. Chernikov 545f1220db8SAlexander V. Chernikov /* 546d3a4f924SAlexander V. Chernikov * High-level 'get' cmds sysctl handlers 547d3a4f924SAlexander V. Chernikov */ 548d3a4f924SAlexander V. Chernikov 549d3a4f924SAlexander V. Chernikov /* 550d3a4f924SAlexander V. Chernikov * Get buffer size needed to list info for all tables. 551d3a4f924SAlexander V. Chernikov * Data layout: 552d3a4f924SAlexander V. Chernikov * Request: [ empty ], size = sizeof(ipfw_obj_lheader) 553d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ] 554d3a4f924SAlexander V. Chernikov * 555d3a4f924SAlexander V. Chernikov * Returns 0 on success 556f1220db8SAlexander V. Chernikov */ 557f1220db8SAlexander V. Chernikov int 5582d99a349SAlexander V. Chernikov ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 559f1220db8SAlexander V. Chernikov { 560f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 561f1220db8SAlexander V. Chernikov 5622d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 5632d99a349SAlexander V. Chernikov if (olh == NULL) 564d3a4f924SAlexander V. Chernikov return (EINVAL); 565d3a4f924SAlexander V. Chernikov 566f1220db8SAlexander V. Chernikov olh->size = sizeof(*olh); /* Make export_table store needed size */ 567f1220db8SAlexander V. Chernikov 568f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 5692d99a349SAlexander V. Chernikov export_tables(ch, olh, sd); 570f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 571f1220db8SAlexander V. Chernikov 5722d99a349SAlexander V. Chernikov return (0); 573f1220db8SAlexander V. Chernikov } 574f1220db8SAlexander V. Chernikov 575d3a4f924SAlexander V. Chernikov /* 576d3a4f924SAlexander V. Chernikov * Lists all tables currently available in kernel. 577d3a4f924SAlexander V. Chernikov * Data layout: 578d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 579d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ] 580d3a4f924SAlexander V. Chernikov * 581d3a4f924SAlexander V. Chernikov * Returns 0 on success 582d3a4f924SAlexander V. Chernikov */ 583f1220db8SAlexander V. Chernikov int 5842d99a349SAlexander V. Chernikov ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 585f1220db8SAlexander V. Chernikov { 586f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 587d3a4f924SAlexander V. Chernikov uint32_t sz; 588f1220db8SAlexander V. Chernikov int error; 589f1220db8SAlexander V. Chernikov 5902d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 5912d99a349SAlexander V. Chernikov if (olh == NULL) 592d3a4f924SAlexander V. Chernikov return (EINVAL); 593d3a4f924SAlexander V. Chernikov 594f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 595f1220db8SAlexander V. Chernikov sz = ipfw_objhash_count(CHAIN_TO_NI(ch)); 5962d99a349SAlexander V. Chernikov 5972d99a349SAlexander V. Chernikov if (sd->valsize < sz) { 5982d99a349SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 5992d99a349SAlexander V. Chernikov return (ENOMEM); 6002d99a349SAlexander V. Chernikov } 6012d99a349SAlexander V. Chernikov 6022d99a349SAlexander V. Chernikov error = export_tables(ch, olh, sd); 603f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 604f1220db8SAlexander V. Chernikov 605f1220db8SAlexander V. Chernikov return (error); 606f1220db8SAlexander V. Chernikov } 607f1220db8SAlexander V. Chernikov 608f1220db8SAlexander V. Chernikov /* 6092d99a349SAlexander V. Chernikov * Store table info to buffer provided by @sd. 610d3a4f924SAlexander V. Chernikov * Data layout: 611d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info(empty)] 612d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ] 613d3a4f924SAlexander V. Chernikov * 614d3a4f924SAlexander V. Chernikov * Returns 0 on success. 615d3a4f924SAlexander V. Chernikov */ 616d3a4f924SAlexander V. Chernikov int 6172d99a349SAlexander V. Chernikov ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd) 618d3a4f924SAlexander V. Chernikov { 619d3a4f924SAlexander V. Chernikov struct _ipfw_obj_header *oh; 620d3a4f924SAlexander V. Chernikov struct table_config *tc; 621d3a4f924SAlexander V. Chernikov struct tid_info ti; 622d3a4f924SAlexander V. Chernikov size_t sz; 623d3a4f924SAlexander V. Chernikov 624d3a4f924SAlexander V. Chernikov sz = sizeof(*oh) + sizeof(ipfw_xtable_info); 6252d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 6262d99a349SAlexander V. Chernikov if (oh == NULL) 627d3a4f924SAlexander V. Chernikov return (EINVAL); 628d3a4f924SAlexander V. Chernikov 629d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 630d3a4f924SAlexander V. Chernikov 631d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 632d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 633d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 634d3a4f924SAlexander V. Chernikov return (ESRCH); 635d3a4f924SAlexander V. Chernikov } 636d3a4f924SAlexander V. Chernikov 637d3a4f924SAlexander V. Chernikov export_table_info(tc, (ipfw_xtable_info *)(oh + 1)); 638d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 639d3a4f924SAlexander V. Chernikov 6402d99a349SAlexander V. Chernikov return (0); 641d3a4f924SAlexander V. Chernikov } 642d3a4f924SAlexander V. Chernikov 643f1220db8SAlexander V. Chernikov struct dump_args { 644f1220db8SAlexander V. Chernikov struct table_info *ti; 645f1220db8SAlexander V. Chernikov struct table_config *tc; 6462d99a349SAlexander V. Chernikov struct sockopt_data *sd; 647f1220db8SAlexander V. Chernikov uint32_t cnt; 648f1220db8SAlexander V. Chernikov uint16_t uidx; 6492d99a349SAlexander V. Chernikov ipfw_table_entry *ent; 6502d99a349SAlexander V. Chernikov uint32_t size; 651f1220db8SAlexander V. Chernikov }; 652f1220db8SAlexander V. Chernikov 653f1220db8SAlexander V. Chernikov int 6542d99a349SAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 6552d99a349SAlexander V. Chernikov struct sockopt_data *sd) 656f1220db8SAlexander V. Chernikov { 657d3a4f924SAlexander V. Chernikov int error; 658d3a4f924SAlexander V. Chernikov 659d3a4f924SAlexander V. Chernikov switch (op3->version) { 660d3a4f924SAlexander V. Chernikov case 0: 6612d99a349SAlexander V. Chernikov error = ipfw_dump_table_v0(ch, sd); 662d3a4f924SAlexander V. Chernikov break; 663d3a4f924SAlexander V. Chernikov case 1: 6642d99a349SAlexander V. Chernikov error = ipfw_dump_table_v1(ch, sd); 665d3a4f924SAlexander V. Chernikov break; 666d3a4f924SAlexander V. Chernikov default: 667d3a4f924SAlexander V. Chernikov error = ENOTSUP; 668d3a4f924SAlexander V. Chernikov } 669d3a4f924SAlexander V. Chernikov 670d3a4f924SAlexander V. Chernikov return (error); 671d3a4f924SAlexander V. Chernikov } 672d3a4f924SAlexander V. Chernikov 673d3a4f924SAlexander V. Chernikov /* 674d3a4f924SAlexander V. Chernikov * Dumps all table data 6752d99a349SAlexander V. Chernikov * Data layout (version 1)(current): 6762d99a349SAlexander V. Chernikov * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size 6772d99a349SAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_table_xentry x N ] 678d3a4f924SAlexander V. Chernikov * 679d3a4f924SAlexander V. Chernikov * Returns 0 on success 680d3a4f924SAlexander V. Chernikov */ 681d3a4f924SAlexander V. Chernikov static int 6822d99a349SAlexander V. Chernikov ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd) 683d3a4f924SAlexander V. Chernikov { 684f1220db8SAlexander V. Chernikov struct _ipfw_obj_header *oh; 685f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 686f1220db8SAlexander V. Chernikov struct tid_info ti; 687f1220db8SAlexander V. Chernikov struct table_config *tc; 688f1220db8SAlexander V. Chernikov struct table_algo *ta; 689f1220db8SAlexander V. Chernikov struct dump_args da; 690d3a4f924SAlexander V. Chernikov uint32_t sz; 691f1220db8SAlexander V. Chernikov 6922d99a349SAlexander V. Chernikov sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 6932d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 6942d99a349SAlexander V. Chernikov if (oh == NULL) 695d3a4f924SAlexander V. Chernikov return (EINVAL); 696d3a4f924SAlexander V. Chernikov 6972d99a349SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 698d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 699f1220db8SAlexander V. Chernikov 700f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 701f1220db8SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 702f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 703f1220db8SAlexander V. Chernikov return (ESRCH); 704f1220db8SAlexander V. Chernikov } 705f1220db8SAlexander V. Chernikov export_table_info(tc, i); 7062d99a349SAlexander V. Chernikov sz = tc->count; 7072d99a349SAlexander V. Chernikov 7082d99a349SAlexander V. Chernikov if (sd->valsize < sz + tc->count * sizeof(ipfw_table_xentry)) { 7092d99a349SAlexander V. Chernikov 7102d99a349SAlexander V. Chernikov /* 7112d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 7122d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 7132d99a349SAlexander V. Chernikov * relevant table info including size, so we 7142d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 7152d99a349SAlexander V. Chernikov */ 716f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 7172d99a349SAlexander V. Chernikov return (ENOMEM); 718f1220db8SAlexander V. Chernikov } 719f1220db8SAlexander V. Chernikov 720f1220db8SAlexander V. Chernikov /* 721f1220db8SAlexander V. Chernikov * Do the actual dump in eXtended format 722f1220db8SAlexander V. Chernikov */ 723d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 724f1220db8SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 725f1220db8SAlexander V. Chernikov da.tc = tc; 7262d99a349SAlexander V. Chernikov da.sd = sd; 727f1220db8SAlexander V. Chernikov 728f1220db8SAlexander V. Chernikov ta = tc->ta; 729f1220db8SAlexander V. Chernikov 730f1220db8SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 731f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 732f1220db8SAlexander V. Chernikov 733f1220db8SAlexander V. Chernikov return (0); 734f1220db8SAlexander V. Chernikov } 735f1220db8SAlexander V. Chernikov 736d3a4f924SAlexander V. Chernikov /* 737d3a4f924SAlexander V. Chernikov * Dumps all table data 7382d99a349SAlexander V. Chernikov * Data layout (version 0)(legacy): 739d3a4f924SAlexander V. Chernikov * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE() 740d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_xtable ipfw_table_xentry x N ] 741d3a4f924SAlexander V. Chernikov * 742d3a4f924SAlexander V. Chernikov * Returns 0 on success 743d3a4f924SAlexander V. Chernikov */ 744d3a4f924SAlexander V. Chernikov static int 7452d99a349SAlexander V. Chernikov ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd) 746d3a4f924SAlexander V. Chernikov { 747d3a4f924SAlexander V. Chernikov ipfw_xtable *xtbl; 748d3a4f924SAlexander V. Chernikov struct tid_info ti; 749d3a4f924SAlexander V. Chernikov struct table_config *tc; 750d3a4f924SAlexander V. Chernikov struct table_algo *ta; 751d3a4f924SAlexander V. Chernikov struct dump_args da; 752d3a4f924SAlexander V. Chernikov size_t sz; 753d3a4f924SAlexander V. Chernikov 7542d99a349SAlexander V. Chernikov xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable)); 7552d99a349SAlexander V. Chernikov if (xtbl == NULL) 756d3a4f924SAlexander V. Chernikov return (EINVAL); 757d3a4f924SAlexander V. Chernikov 758d3a4f924SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 759d3a4f924SAlexander V. Chernikov ti.set = 0; /* XXX: No way to specify set */ 760d3a4f924SAlexander V. Chernikov ti.uidx = xtbl->tbl; 761d3a4f924SAlexander V. Chernikov 762d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 763d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 764d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 765d3a4f924SAlexander V. Chernikov return (0); 766d3a4f924SAlexander V. Chernikov } 767d3a4f924SAlexander V. Chernikov sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); 7682d99a349SAlexander V. Chernikov 7692d99a349SAlexander V. Chernikov xtbl->cnt = tc->count; 7702d99a349SAlexander V. Chernikov xtbl->size = sz; 7712d99a349SAlexander V. Chernikov xtbl->type = tc->no.type; 7722d99a349SAlexander V. Chernikov xtbl->tbl = ti.uidx; 7732d99a349SAlexander V. Chernikov 7742d99a349SAlexander V. Chernikov if (sd->valsize < sz) { 7752d99a349SAlexander V. Chernikov 7762d99a349SAlexander V. Chernikov /* 7772d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 7782d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 7792d99a349SAlexander V. Chernikov * relevant table info including size, so we 7802d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 7812d99a349SAlexander V. Chernikov */ 782d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 7832d99a349SAlexander V. Chernikov return (ENOMEM); 784d3a4f924SAlexander V. Chernikov } 785d3a4f924SAlexander V. Chernikov 786d3a4f924SAlexander V. Chernikov /* Do the actual dump in eXtended format */ 787d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 788d3a4f924SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 789d3a4f924SAlexander V. Chernikov da.tc = tc; 7902d99a349SAlexander V. Chernikov da.sd = sd; 7912d99a349SAlexander V. Chernikov 792d3a4f924SAlexander V. Chernikov ta = tc->ta; 793d3a4f924SAlexander V. Chernikov 794d3a4f924SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 795d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 796d3a4f924SAlexander V. Chernikov 7972d99a349SAlexander V. Chernikov return (0); 798d3a4f924SAlexander V. Chernikov } 799d3a4f924SAlexander V. Chernikov 800d3a4f924SAlexander V. Chernikov /* 8019490a627SAlexander V. Chernikov * High-level setsockopt cmds 8029490a627SAlexander V. Chernikov */ 8039490a627SAlexander V. Chernikov int 8049490a627SAlexander V. Chernikov ipfw_modify_table(struct ip_fw_chain *ch, struct sockopt *sopt, 8059490a627SAlexander V. Chernikov ip_fw3_opheader *op3) 8069490a627SAlexander V. Chernikov { 8079490a627SAlexander V. Chernikov 8089490a627SAlexander V. Chernikov return (ENOTSUP); 8099490a627SAlexander V. Chernikov } 8109490a627SAlexander V. Chernikov 8119490a627SAlexander V. Chernikov /* 8129490a627SAlexander V. Chernikov * Creates new table. 8139490a627SAlexander V. Chernikov * Data layout: 8149490a627SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 8159490a627SAlexander V. Chernikov * 8169490a627SAlexander V. Chernikov * Returns 0 on success 8179490a627SAlexander V. Chernikov */ 8189490a627SAlexander V. Chernikov int 8199490a627SAlexander V. Chernikov ipfw_create_table(struct ip_fw_chain *ch, struct sockopt *sopt, 8209490a627SAlexander V. Chernikov ip_fw3_opheader *op3) 8219490a627SAlexander V. Chernikov { 8229490a627SAlexander V. Chernikov struct _ipfw_obj_header *oh; 8239490a627SAlexander V. Chernikov ipfw_xtable_info *i; 8249490a627SAlexander V. Chernikov char *tname, *aname; 8259490a627SAlexander V. Chernikov struct tid_info ti; 8269490a627SAlexander V. Chernikov struct namedobj_instance *ni; 8279490a627SAlexander V. Chernikov struct table_config *tc; 8289490a627SAlexander V. Chernikov struct table_algo *ta; 8299490a627SAlexander V. Chernikov uint16_t kidx; 8309490a627SAlexander V. Chernikov 8319490a627SAlexander V. Chernikov if (sopt->sopt_valsize < sizeof(*oh) + sizeof(ipfw_xtable_info)) 8329490a627SAlexander V. Chernikov return (EINVAL); 8339490a627SAlexander V. Chernikov 8349490a627SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)op3; 8359490a627SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 8369490a627SAlexander V. Chernikov 8379490a627SAlexander V. Chernikov /* 8389490a627SAlexander V. Chernikov * Verify user-supplied strings. 8392d99a349SAlexander V. Chernikov * Check for null-terminated/zero-length strings/ 8409490a627SAlexander V. Chernikov */ 8419490a627SAlexander V. Chernikov tname = i->tablename; 8429490a627SAlexander V. Chernikov aname = i->algoname; 8439490a627SAlexander V. Chernikov if (strnlen(tname, sizeof(i->tablename)) == sizeof(i->tablename) || 8449490a627SAlexander V. Chernikov tname[0] == '\0' || 8459490a627SAlexander V. Chernikov strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname)) 8469490a627SAlexander V. Chernikov return (EINVAL); 8479490a627SAlexander V. Chernikov 8489490a627SAlexander V. Chernikov if (aname[0] == '\0') { 8499490a627SAlexander V. Chernikov /* Use default algorithm */ 8509490a627SAlexander V. Chernikov aname = NULL; 8519490a627SAlexander V. Chernikov } 8529490a627SAlexander V. Chernikov 8539490a627SAlexander V. Chernikov objheader_to_ti(oh, &ti); 8549490a627SAlexander V. Chernikov 8559490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 8569490a627SAlexander V. Chernikov 8579490a627SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 8589490a627SAlexander V. Chernikov if ((tc = find_table(ni, &ti)) != NULL) { 8599490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 8609490a627SAlexander V. Chernikov return (EEXIST); 8619490a627SAlexander V. Chernikov } 8629490a627SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(ch), &ti, aname); 8639490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 8649490a627SAlexander V. Chernikov 8659490a627SAlexander V. Chernikov if (ta == NULL) 8669490a627SAlexander V. Chernikov return (ENOTSUP); 8679490a627SAlexander V. Chernikov 8689490a627SAlexander V. Chernikov if ((tc = alloc_table_config(ni, &ti, ta, aname)) == NULL) 8699490a627SAlexander V. Chernikov return (ENOMEM); 8709490a627SAlexander V. Chernikov 8719490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 8729490a627SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, ti.set, &kidx) != 0) { 8739490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 8749490a627SAlexander V. Chernikov printf("Unable to allocate table index for table %s in set %u." 8759490a627SAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 8769490a627SAlexander V. Chernikov tname, ti.set); 8779490a627SAlexander V. Chernikov free_table_config(ni, tc); 8789490a627SAlexander V. Chernikov return (EBUSY); 8799490a627SAlexander V. Chernikov } 8809490a627SAlexander V. Chernikov 8819490a627SAlexander V. Chernikov tc->no.kidx = kidx; 8829490a627SAlexander V. Chernikov 8839490a627SAlexander V. Chernikov IPFW_WLOCK(ch); 8849490a627SAlexander V. Chernikov link_table(ch, tc); 8859490a627SAlexander V. Chernikov IPFW_WUNLOCK(ch); 8869490a627SAlexander V. Chernikov 8879490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 8889490a627SAlexander V. Chernikov 8899490a627SAlexander V. Chernikov return (0); 8909490a627SAlexander V. Chernikov } 8919490a627SAlexander V. Chernikov 892d3a4f924SAlexander V. Chernikov void 893d3a4f924SAlexander V. Chernikov objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti) 894d3a4f924SAlexander V. Chernikov { 895d3a4f924SAlexander V. Chernikov 896d3a4f924SAlexander V. Chernikov memset(ti, 0, sizeof(struct tid_info)); 897d3a4f924SAlexander V. Chernikov ti->set = oh->set; 898d3a4f924SAlexander V. Chernikov ti->uidx = oh->idx; 899d3a4f924SAlexander V. Chernikov ti->tlvs = &oh->ntlv; 900d3a4f924SAlexander V. Chernikov ti->tlen = oh->ntlv.head.length; 901d3a4f924SAlexander V. Chernikov } 902d3a4f924SAlexander V. Chernikov 903563b5ab1SAlexander V. Chernikov int 904563b5ab1SAlexander V. Chernikov ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx, 905563b5ab1SAlexander V. Chernikov struct sockopt_data *sd) 906563b5ab1SAlexander V. Chernikov { 907563b5ab1SAlexander V. Chernikov struct namedobj_instance *ni; 908563b5ab1SAlexander V. Chernikov struct named_object *no; 909563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 910563b5ab1SAlexander V. Chernikov 911563b5ab1SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 912563b5ab1SAlexander V. Chernikov 913563b5ab1SAlexander V. Chernikov no = ipfw_objhash_lookup_idx(ni, 0, kidx); 914563b5ab1SAlexander V. Chernikov KASSERT(no != NULL, ("invalid table kidx passed")); 915563b5ab1SAlexander V. Chernikov 916563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 917563b5ab1SAlexander V. Chernikov if (ntlv == NULL) 918563b5ab1SAlexander V. Chernikov return (ENOMEM); 919563b5ab1SAlexander V. Chernikov 920563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 921563b5ab1SAlexander V. Chernikov ntlv->head.length = sizeof(*ntlv); 922563b5ab1SAlexander V. Chernikov ntlv->idx = no->kidx; 923563b5ab1SAlexander V. Chernikov strlcpy(ntlv->name, no->name, sizeof(ntlv->name)); 924563b5ab1SAlexander V. Chernikov 925563b5ab1SAlexander V. Chernikov return (0); 926563b5ab1SAlexander V. Chernikov } 927563b5ab1SAlexander V. Chernikov 9289f7d47b0SAlexander V. Chernikov static void 9299f7d47b0SAlexander V. Chernikov export_table_info(struct table_config *tc, ipfw_xtable_info *i) 9309f7d47b0SAlexander V. Chernikov { 9319f7d47b0SAlexander V. Chernikov 9329f7d47b0SAlexander V. Chernikov i->type = tc->no.type; 9339f7d47b0SAlexander V. Chernikov i->ftype = tc->ftype; 9349f7d47b0SAlexander V. Chernikov i->atype = tc->ta->idx; 9359f7d47b0SAlexander V. Chernikov i->set = tc->no.set; 9369f7d47b0SAlexander V. Chernikov i->kidx = tc->no.kidx; 9379f7d47b0SAlexander V. Chernikov i->refcnt = tc->no.refcnt; 9389f7d47b0SAlexander V. Chernikov i->count = tc->count; 9399f7d47b0SAlexander V. Chernikov i->size = tc->count * sizeof(ipfw_table_xentry); 940f1220db8SAlexander V. Chernikov i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 9419f7d47b0SAlexander V. Chernikov strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); 9429f7d47b0SAlexander V. Chernikov } 9439f7d47b0SAlexander V. Chernikov 9449f7d47b0SAlexander V. Chernikov static void 9459f7d47b0SAlexander V. Chernikov export_table_internal(struct namedobj_instance *ni, struct named_object *no, 9469f7d47b0SAlexander V. Chernikov void *arg) 9473b3a8eb9SGleb Smirnoff { 9489f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i; 9492d99a349SAlexander V. Chernikov struct sockopt_data *sd; 9503b3a8eb9SGleb Smirnoff 9512d99a349SAlexander V. Chernikov sd = (struct sockopt_data *)arg; 9522d99a349SAlexander V. Chernikov i = (ipfw_xtable_info *)ipfw_get_sopt_space(sd, sizeof(*i)); 9532d99a349SAlexander V. Chernikov KASSERT(i == 0, ("previously checked buffer is not enough")); 9549f7d47b0SAlexander V. Chernikov 9559f7d47b0SAlexander V. Chernikov export_table_info((struct table_config *)no, i); 9569f7d47b0SAlexander V. Chernikov } 9579f7d47b0SAlexander V. Chernikov 958f1220db8SAlexander V. Chernikov /* 959f1220db8SAlexander V. Chernikov * Export all tables as ipfw_xtable_info structures to 9602d99a349SAlexander V. Chernikov * storage provided by @sd. 961f1220db8SAlexander V. Chernikov * Returns 0 on success. 962f1220db8SAlexander V. Chernikov */ 963f1220db8SAlexander V. Chernikov static int 9642d99a349SAlexander V. Chernikov export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 9652d99a349SAlexander V. Chernikov struct sockopt_data *sd) 9669f7d47b0SAlexander V. Chernikov { 9679f7d47b0SAlexander V. Chernikov uint32_t size; 9689f7d47b0SAlexander V. Chernikov uint32_t count; 9699f7d47b0SAlexander V. Chernikov 9709f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 9719f7d47b0SAlexander V. Chernikov size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 9722d99a349SAlexander V. Chernikov 9732d99a349SAlexander V. Chernikov /* Fill in header regadless of buffer size */ 974f1220db8SAlexander V. Chernikov olh->count = count; 975f1220db8SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 9762d99a349SAlexander V. Chernikov 9772d99a349SAlexander V. Chernikov if (size > olh->size) { 9782d99a349SAlexander V. Chernikov /* Store necessary size */ 9792d99a349SAlexander V. Chernikov olh->size = size; 9809f7d47b0SAlexander V. Chernikov return (ENOMEM); 981f1220db8SAlexander V. Chernikov } 9829f7d47b0SAlexander V. Chernikov olh->size = size; 9832d99a349SAlexander V. Chernikov 9842d99a349SAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, sd); 9859f7d47b0SAlexander V. Chernikov 9863b3a8eb9SGleb Smirnoff return (0); 9873b3a8eb9SGleb Smirnoff } 9883b3a8eb9SGleb Smirnoff 9893b3a8eb9SGleb Smirnoff int 990b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 9913b3a8eb9SGleb Smirnoff { 992b074b7bbSAlexander V. Chernikov struct table_config *tc; 9933b3a8eb9SGleb Smirnoff 994b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 995b074b7bbSAlexander V. Chernikov return (ESRCH); 9969f7d47b0SAlexander V. Chernikov *cnt = tc->count; 9973b3a8eb9SGleb Smirnoff return (0); 9983b3a8eb9SGleb Smirnoff } 9993b3a8eb9SGleb Smirnoff 10009f7d47b0SAlexander V. Chernikov 10019f7d47b0SAlexander V. Chernikov int 10029f7d47b0SAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 10033b3a8eb9SGleb Smirnoff { 10049f7d47b0SAlexander V. Chernikov struct table_config *tc; 10059f7d47b0SAlexander V. Chernikov 1006d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) { 1007d3a4f924SAlexander V. Chernikov *cnt = 0; 10089f7d47b0SAlexander V. Chernikov return (0); /* 'table all list' requires success */ 1009d3a4f924SAlexander V. Chernikov } 10109f7d47b0SAlexander V. Chernikov *cnt = tc->count * sizeof(ipfw_table_xentry); 10119f7d47b0SAlexander V. Chernikov if (tc->count > 0) 10129f7d47b0SAlexander V. Chernikov *cnt += sizeof(ipfw_xtable); 10139f7d47b0SAlexander V. Chernikov return (0); 10149f7d47b0SAlexander V. Chernikov } 10159f7d47b0SAlexander V. Chernikov 10169f7d47b0SAlexander V. Chernikov static int 10179f7d47b0SAlexander V. Chernikov dump_table_entry(void *e, void *arg) 10189f7d47b0SAlexander V. Chernikov { 10199f7d47b0SAlexander V. Chernikov struct dump_args *da; 10209f7d47b0SAlexander V. Chernikov struct table_config *tc; 10219f7d47b0SAlexander V. Chernikov struct table_algo *ta; 10223b3a8eb9SGleb Smirnoff ipfw_table_entry *ent; 10233b3a8eb9SGleb Smirnoff 10249f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 10259f7d47b0SAlexander V. Chernikov 10269f7d47b0SAlexander V. Chernikov tc = da->tc; 10279f7d47b0SAlexander V. Chernikov ta = tc->ta; 10289f7d47b0SAlexander V. Chernikov 10299f7d47b0SAlexander V. Chernikov /* Out of memory, returning */ 1030f1220db8SAlexander V. Chernikov if (da->cnt == da->size) 10313b3a8eb9SGleb Smirnoff return (1); 1032f1220db8SAlexander V. Chernikov ent = da->ent++; 1033f1220db8SAlexander V. Chernikov ent->tbl = da->uidx; 1034f1220db8SAlexander V. Chernikov da->cnt++; 10359f7d47b0SAlexander V. Chernikov 10369f7d47b0SAlexander V. Chernikov return (ta->dump_entry(tc->astate, da->ti, e, ent)); 10373b3a8eb9SGleb Smirnoff } 10383b3a8eb9SGleb Smirnoff 1039f1220db8SAlexander V. Chernikov /* 1040f1220db8SAlexander V. Chernikov * Dumps table in pre-8.1 legacy format. 1041f1220db8SAlexander V. Chernikov */ 10423b3a8eb9SGleb Smirnoff int 1043f1220db8SAlexander V. Chernikov ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti, 1044f1220db8SAlexander V. Chernikov ipfw_table *tbl) 10453b3a8eb9SGleb Smirnoff { 1046b074b7bbSAlexander V. Chernikov struct table_config *tc; 10479f7d47b0SAlexander V. Chernikov struct table_algo *ta; 10489f7d47b0SAlexander V. Chernikov struct dump_args da; 10493b3a8eb9SGleb Smirnoff 10503b3a8eb9SGleb Smirnoff tbl->cnt = 0; 10513b3a8eb9SGleb Smirnoff 1052b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1053b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 10549f7d47b0SAlexander V. Chernikov 10559f7d47b0SAlexander V. Chernikov ta = tc->ta; 10569f7d47b0SAlexander V. Chernikov 10579f7d47b0SAlexander V. Chernikov if (ta->dump_entry == NULL) 10589f7d47b0SAlexander V. Chernikov return (0); /* Legacy dump support is not necessary */ 10599f7d47b0SAlexander V. Chernikov 1060d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 10619f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 10629f7d47b0SAlexander V. Chernikov da.tc = tc; 1063f1220db8SAlexander V. Chernikov da.ent = &tbl->ent[0]; 1064f1220db8SAlexander V. Chernikov da.size = tbl->size; 10659f7d47b0SAlexander V. Chernikov 10669f7d47b0SAlexander V. Chernikov tbl->cnt = 0; 10679f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_entry, &da); 1068f1220db8SAlexander V. Chernikov tbl->cnt = da.cnt; 10699f7d47b0SAlexander V. Chernikov 10703b3a8eb9SGleb Smirnoff return (0); 10713b3a8eb9SGleb Smirnoff } 10723b3a8eb9SGleb Smirnoff 10739490a627SAlexander V. Chernikov /* 10749490a627SAlexander V. Chernikov * Dumps table entry in eXtended format (current). 10759490a627SAlexander V. Chernikov */ 10763b3a8eb9SGleb Smirnoff static int 10779f7d47b0SAlexander V. Chernikov dump_table_xentry(void *e, void *arg) 10783b3a8eb9SGleb Smirnoff { 10799f7d47b0SAlexander V. Chernikov struct dump_args *da; 10809f7d47b0SAlexander V. Chernikov struct table_config *tc; 10819f7d47b0SAlexander V. Chernikov struct table_algo *ta; 10823b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 10833b3a8eb9SGleb Smirnoff 10849f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 10859f7d47b0SAlexander V. Chernikov 10869f7d47b0SAlexander V. Chernikov tc = da->tc; 10879f7d47b0SAlexander V. Chernikov ta = tc->ta; 10889f7d47b0SAlexander V. Chernikov 10892d99a349SAlexander V. Chernikov xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent)); 10903b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 10912d99a349SAlexander V. Chernikov if (xent == NULL) 10923b3a8eb9SGleb Smirnoff return (1); 10933b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 1094f1220db8SAlexander V. Chernikov xent->tbl = da->uidx; 10959f7d47b0SAlexander V. Chernikov 10969f7d47b0SAlexander V. Chernikov return (ta->dump_xentry(tc->astate, da->ti, e, xent)); 10979f7d47b0SAlexander V. Chernikov } 10989f7d47b0SAlexander V. Chernikov 10999f7d47b0SAlexander V. Chernikov /* 11009f7d47b0SAlexander V. Chernikov * Table algorithms 11019f7d47b0SAlexander V. Chernikov */ 11023b3a8eb9SGleb Smirnoff 11039f7d47b0SAlexander V. Chernikov /* 11049490a627SAlexander V. Chernikov * Finds algoritm by index, table type or supplied name 11059f7d47b0SAlexander V. Chernikov */ 11069f7d47b0SAlexander V. Chernikov static struct table_algo * 11079490a627SAlexander V. Chernikov find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name) 11089f7d47b0SAlexander V. Chernikov { 11099490a627SAlexander V. Chernikov int i, l; 11109490a627SAlexander V. Chernikov struct table_algo *ta; 11119f7d47b0SAlexander V. Chernikov 11129f7d47b0SAlexander V. Chernikov /* Search by index */ 11139f7d47b0SAlexander V. Chernikov if (ti->atype != 0) { 11149f7d47b0SAlexander V. Chernikov if (ti->atype > tcfg->algo_count) 11159f7d47b0SAlexander V. Chernikov return (NULL); 11169f7d47b0SAlexander V. Chernikov return (tcfg->algo[ti->atype]); 11179f7d47b0SAlexander V. Chernikov } 11189f7d47b0SAlexander V. Chernikov 11199490a627SAlexander V. Chernikov /* Search by name if supplied */ 11209490a627SAlexander V. Chernikov if (name != NULL) { 11219490a627SAlexander V. Chernikov /* TODO: better search */ 11229490a627SAlexander V. Chernikov for (i = 1; i <= tcfg->algo_count; i++) { 11239490a627SAlexander V. Chernikov ta = tcfg->algo[i]; 11249490a627SAlexander V. Chernikov 11259490a627SAlexander V. Chernikov /* 11269490a627SAlexander V. Chernikov * One can supply additional algorithm 11279490a627SAlexander V. Chernikov * parameters so we compare only the first word 11289490a627SAlexander V. Chernikov * of supplied name: 11299490a627SAlexander V. Chernikov * 'hash_cidr hsize=32' 11309490a627SAlexander V. Chernikov * '^^^^^^^^^' 11319490a627SAlexander V. Chernikov * 11329490a627SAlexander V. Chernikov */ 11339490a627SAlexander V. Chernikov l = strlen(ta->name); 11349490a627SAlexander V. Chernikov if (strncmp(name, ta->name, l) == 0) { 11359490a627SAlexander V. Chernikov if (name[l] == '\0' || name[l] == ' ') 11369490a627SAlexander V. Chernikov return (ta); 11379490a627SAlexander V. Chernikov } 11389490a627SAlexander V. Chernikov } 11399490a627SAlexander V. Chernikov 11409490a627SAlexander V. Chernikov return (NULL); 11419490a627SAlexander V. Chernikov } 11429490a627SAlexander V. Chernikov 11439f7d47b0SAlexander V. Chernikov /* Search by type */ 11449f7d47b0SAlexander V. Chernikov switch (ti->type) { 11453b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 11469f7d47b0SAlexander V. Chernikov return (&radix_cidr); 11473b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 11489f7d47b0SAlexander V. Chernikov return (&radix_iface); 11493b3a8eb9SGleb Smirnoff } 11503b3a8eb9SGleb Smirnoff 11519f7d47b0SAlexander V. Chernikov return (NULL); 11523b3a8eb9SGleb Smirnoff } 11533b3a8eb9SGleb Smirnoff 11549f7d47b0SAlexander V. Chernikov void 11559f7d47b0SAlexander V. Chernikov ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta) 11563b3a8eb9SGleb Smirnoff { 11579f7d47b0SAlexander V. Chernikov struct tables_config *tcfg; 11583b3a8eb9SGleb Smirnoff 11599f7d47b0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 1160b074b7bbSAlexander V. Chernikov 11619f7d47b0SAlexander V. Chernikov KASSERT(tcfg->algo_count < 255, ("Increase algo array size")); 11629f7d47b0SAlexander V. Chernikov 11639f7d47b0SAlexander V. Chernikov tcfg->algo[++tcfg->algo_count] = ta; 11649f7d47b0SAlexander V. Chernikov ta->idx = tcfg->algo_count; 11653b3a8eb9SGleb Smirnoff } 11663b3a8eb9SGleb Smirnoff 11679f7d47b0SAlexander V. Chernikov 1168b074b7bbSAlexander V. Chernikov /* 1169b074b7bbSAlexander V. Chernikov * Tables rewriting code 1170b074b7bbSAlexander V. Chernikov * 1171b074b7bbSAlexander V. Chernikov */ 1172b074b7bbSAlexander V. Chernikov 1173b074b7bbSAlexander V. Chernikov /* 1174b074b7bbSAlexander V. Chernikov * Determine table number and lookup type for @cmd. 1175b074b7bbSAlexander V. Chernikov * Fill @tbl and @type with appropriate values. 1176b074b7bbSAlexander V. Chernikov * Returns 0 for relevant opcodes, 1 otherwise. 1177b074b7bbSAlexander V. Chernikov */ 1178b074b7bbSAlexander V. Chernikov static int 1179b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 1180b074b7bbSAlexander V. Chernikov { 1181b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1182b074b7bbSAlexander V. Chernikov int skip; 1183b074b7bbSAlexander V. Chernikov uint16_t v; 1184b074b7bbSAlexander V. Chernikov 1185b074b7bbSAlexander V. Chernikov skip = 1; 1186b074b7bbSAlexander V. Chernikov 1187b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1188b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1189b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1190b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1191b074b7bbSAlexander V. Chernikov *puidx = cmd->arg1; 1192b074b7bbSAlexander V. Chernikov /* Assume CIDR by default */ 1193b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 1194b074b7bbSAlexander V. Chernikov skip = 0; 1195b074b7bbSAlexander V. Chernikov 1196b074b7bbSAlexander V. Chernikov if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { 1197b074b7bbSAlexander V. Chernikov /* 1198b074b7bbSAlexander V. Chernikov * generic lookup. The key must be 1199b074b7bbSAlexander V. Chernikov * in 32bit big-endian format. 1200b074b7bbSAlexander V. Chernikov */ 1201b074b7bbSAlexander V. Chernikov v = ((ipfw_insn_u32 *)cmd)->d[1]; 1202b074b7bbSAlexander V. Chernikov switch (v) { 1203b074b7bbSAlexander V. Chernikov case 0: 1204b074b7bbSAlexander V. Chernikov case 1: 1205b074b7bbSAlexander V. Chernikov /* IPv4 src/dst */ 1206b074b7bbSAlexander V. Chernikov break; 1207b074b7bbSAlexander V. Chernikov case 2: 1208b074b7bbSAlexander V. Chernikov case 3: 1209b074b7bbSAlexander V. Chernikov /* src/dst port */ 1210b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 1211b074b7bbSAlexander V. Chernikov break; 1212b074b7bbSAlexander V. Chernikov case 4: 1213b074b7bbSAlexander V. Chernikov /* uid/gid */ 1214b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 1215b074b7bbSAlexander V. Chernikov case 5: 1216b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 1217b074b7bbSAlexander V. Chernikov /* jid */ 1218b074b7bbSAlexander V. Chernikov case 6: 1219b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 1220b074b7bbSAlexander V. Chernikov /* dscp */ 1221b074b7bbSAlexander V. Chernikov break; 1222b074b7bbSAlexander V. Chernikov } 1223b074b7bbSAlexander V. Chernikov } 1224b074b7bbSAlexander V. Chernikov break; 1225b074b7bbSAlexander V. Chernikov case O_XMIT: 1226b074b7bbSAlexander V. Chernikov case O_RECV: 1227b074b7bbSAlexander V. Chernikov case O_VIA: 1228b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1229b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1230b074b7bbSAlexander V. Chernikov if (cmdif->name[0] != '\1') 1231b074b7bbSAlexander V. Chernikov break; 1232b074b7bbSAlexander V. Chernikov 1233b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 1234b074b7bbSAlexander V. Chernikov *puidx = cmdif->p.glob; 1235b074b7bbSAlexander V. Chernikov skip = 0; 1236b074b7bbSAlexander V. Chernikov break; 1237b074b7bbSAlexander V. Chernikov } 1238b074b7bbSAlexander V. Chernikov 1239b074b7bbSAlexander V. Chernikov return (skip); 1240b074b7bbSAlexander V. Chernikov } 1241b074b7bbSAlexander V. Chernikov 1242b074b7bbSAlexander V. Chernikov /* 1243b074b7bbSAlexander V. Chernikov * Sets new table value for given opcode. 1244b074b7bbSAlexander V. Chernikov * Assume the same opcodes as classify_table_opcode() 1245b074b7bbSAlexander V. Chernikov */ 1246b074b7bbSAlexander V. Chernikov static void 1247b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx) 1248b074b7bbSAlexander V. Chernikov { 1249b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1250b074b7bbSAlexander V. Chernikov 1251b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1252b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1253b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1254b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1255b074b7bbSAlexander V. Chernikov cmd->arg1 = idx; 1256b074b7bbSAlexander V. Chernikov break; 1257b074b7bbSAlexander V. Chernikov case O_XMIT: 1258b074b7bbSAlexander V. Chernikov case O_RECV: 1259b074b7bbSAlexander V. Chernikov case O_VIA: 1260b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1261b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1262b074b7bbSAlexander V. Chernikov cmdif->p.glob = idx; 1263b074b7bbSAlexander V. Chernikov break; 1264b074b7bbSAlexander V. Chernikov } 1265b074b7bbSAlexander V. Chernikov } 1266b074b7bbSAlexander V. Chernikov 1267b074b7bbSAlexander V. Chernikov static char * 1268b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx) 1269b074b7bbSAlexander V. Chernikov { 12709f7d47b0SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1271b074b7bbSAlexander V. Chernikov uintptr_t pa, pe; 1272b074b7bbSAlexander V. Chernikov int l; 1273b074b7bbSAlexander V. Chernikov 1274b074b7bbSAlexander V. Chernikov pa = (uintptr_t)tlvs; 1275b074b7bbSAlexander V. Chernikov pe = pa + len; 1276b074b7bbSAlexander V. Chernikov l = 0; 1277b074b7bbSAlexander V. Chernikov for (; pa < pe; pa += l) { 12789f7d47b0SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)pa; 1279b074b7bbSAlexander V. Chernikov l = ntlv->head.length; 1280563b5ab1SAlexander V. Chernikov if (ntlv->head.type != IPFW_TLV_TBL_NAME) 1281b074b7bbSAlexander V. Chernikov continue; 1282b074b7bbSAlexander V. Chernikov if (ntlv->idx != uidx) 1283b074b7bbSAlexander V. Chernikov continue; 1284b074b7bbSAlexander V. Chernikov 1285b074b7bbSAlexander V. Chernikov return (ntlv->name); 1286b074b7bbSAlexander V. Chernikov } 1287b074b7bbSAlexander V. Chernikov 1288b074b7bbSAlexander V. Chernikov return (NULL); 1289b074b7bbSAlexander V. Chernikov } 1290b074b7bbSAlexander V. Chernikov 1291b074b7bbSAlexander V. Chernikov static struct table_config * 1292b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti) 1293b074b7bbSAlexander V. Chernikov { 1294b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1295b074b7bbSAlexander V. Chernikov struct named_object *no; 1296b074b7bbSAlexander V. Chernikov 1297b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1298b074b7bbSAlexander V. Chernikov name = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1299b074b7bbSAlexander V. Chernikov if (name == NULL) 1300b074b7bbSAlexander V. Chernikov return (NULL); 1301b074b7bbSAlexander V. Chernikov } else { 1302b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1303b074b7bbSAlexander V. Chernikov name = bname; 1304b074b7bbSAlexander V. Chernikov } 1305b074b7bbSAlexander V. Chernikov 1306b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_name(ni, ti->set, name); 1307b074b7bbSAlexander V. Chernikov 1308b074b7bbSAlexander V. Chernikov return ((struct table_config *)no); 1309b074b7bbSAlexander V. Chernikov } 1310b074b7bbSAlexander V. Chernikov 1311b074b7bbSAlexander V. Chernikov static struct table_config * 13129f7d47b0SAlexander V. Chernikov alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti, 13139490a627SAlexander V. Chernikov struct table_algo *ta, char *aname) 1314b074b7bbSAlexander V. Chernikov { 1315b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1316b074b7bbSAlexander V. Chernikov struct table_config *tc; 1317b074b7bbSAlexander V. Chernikov int error; 1318b074b7bbSAlexander V. Chernikov 1319b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1320b074b7bbSAlexander V. Chernikov name = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1321b074b7bbSAlexander V. Chernikov if (name == NULL) 1322b074b7bbSAlexander V. Chernikov return (NULL); 1323b074b7bbSAlexander V. Chernikov } else { 1324b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1325b074b7bbSAlexander V. Chernikov name = bname; 1326b074b7bbSAlexander V. Chernikov } 1327b074b7bbSAlexander V. Chernikov 1328b074b7bbSAlexander V. Chernikov tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO); 1329b074b7bbSAlexander V. Chernikov tc->no.name = tc->tablename; 1330b074b7bbSAlexander V. Chernikov tc->no.type = ti->type; 1331b074b7bbSAlexander V. Chernikov tc->no.set = ti->set; 13329f7d47b0SAlexander V. Chernikov tc->ta = ta; 1333b074b7bbSAlexander V. Chernikov strlcpy(tc->tablename, name, sizeof(tc->tablename)); 1334b074b7bbSAlexander V. Chernikov 1335b074b7bbSAlexander V. Chernikov if (ti->tlvs == NULL) { 1336b074b7bbSAlexander V. Chernikov tc->no.compat = 1; 1337b074b7bbSAlexander V. Chernikov tc->no.uidx = ti->uidx; 1338b074b7bbSAlexander V. Chernikov } 1339b074b7bbSAlexander V. Chernikov 1340b074b7bbSAlexander V. Chernikov /* Preallocate data structures for new tables */ 13419490a627SAlexander V. Chernikov error = ta->init(&tc->astate, &tc->ti, aname); 1342b074b7bbSAlexander V. Chernikov if (error != 0) { 1343b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1344b074b7bbSAlexander V. Chernikov return (NULL); 1345b074b7bbSAlexander V. Chernikov } 1346b074b7bbSAlexander V. Chernikov 1347b074b7bbSAlexander V. Chernikov return (tc); 1348b074b7bbSAlexander V. Chernikov } 1349b074b7bbSAlexander V. Chernikov 1350b074b7bbSAlexander V. Chernikov static void 1351b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc) 1352b074b7bbSAlexander V. Chernikov { 1353b074b7bbSAlexander V. Chernikov 1354b074b7bbSAlexander V. Chernikov if (tc->linked == 0) 13559f7d47b0SAlexander V. Chernikov tc->ta->destroy(&tc->astate, &tc->ti); 1356b074b7bbSAlexander V. Chernikov 1357b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1358b074b7bbSAlexander V. Chernikov } 1359b074b7bbSAlexander V. Chernikov 1360b074b7bbSAlexander V. Chernikov /* 1361b074b7bbSAlexander V. Chernikov * Links @tc to @chain table named instance. 1362b074b7bbSAlexander V. Chernikov * Sets appropriate type/states in @chain table info. 1363b074b7bbSAlexander V. Chernikov */ 1364b074b7bbSAlexander V. Chernikov static void 13659f7d47b0SAlexander V. Chernikov link_table(struct ip_fw_chain *ch, struct table_config *tc) 1366b074b7bbSAlexander V. Chernikov { 1367b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 13689f7d47b0SAlexander V. Chernikov struct table_info *ti; 1369b074b7bbSAlexander V. Chernikov uint16_t kidx; 1370b074b7bbSAlexander V. Chernikov 13719f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 13729f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1373b074b7bbSAlexander V. Chernikov 13749f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1375b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1376b074b7bbSAlexander V. Chernikov 1377b074b7bbSAlexander V. Chernikov ipfw_objhash_add(ni, &tc->no); 13789f7d47b0SAlexander V. Chernikov 13799f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 13809f7d47b0SAlexander V. Chernikov *ti = tc->ti; 1381b074b7bbSAlexander V. Chernikov 1382b074b7bbSAlexander V. Chernikov tc->linked = 1; 1383b074b7bbSAlexander V. Chernikov } 1384b074b7bbSAlexander V. Chernikov 1385b074b7bbSAlexander V. Chernikov /* 1386b074b7bbSAlexander V. Chernikov * Unlinks @tc from @chain table named instance. 1387b074b7bbSAlexander V. Chernikov * Zeroes states in @chain and stores them in @tc. 1388b074b7bbSAlexander V. Chernikov */ 1389b074b7bbSAlexander V. Chernikov static void 13909f7d47b0SAlexander V. Chernikov unlink_table(struct ip_fw_chain *ch, struct table_config *tc) 1391b074b7bbSAlexander V. Chernikov { 1392b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 13939f7d47b0SAlexander V. Chernikov struct table_info *ti; 1394b074b7bbSAlexander V. Chernikov uint16_t kidx; 1395b074b7bbSAlexander V. Chernikov 13969f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 13979f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1398b074b7bbSAlexander V. Chernikov 13999f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1400b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1401b074b7bbSAlexander V. Chernikov 14029f7d47b0SAlexander V. Chernikov /* Clear state. @ti copy is already saved inside @tc */ 1403b074b7bbSAlexander V. Chernikov ipfw_objhash_del(ni, &tc->no); 14049f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 14059f7d47b0SAlexander V. Chernikov memset(ti, 0, sizeof(struct table_info)); 1406b074b7bbSAlexander V. Chernikov tc->linked = 0; 1407b074b7bbSAlexander V. Chernikov } 1408b074b7bbSAlexander V. Chernikov 1409b074b7bbSAlexander V. Chernikov /* 1410b074b7bbSAlexander V. Chernikov * Finds named object by @uidx number. 1411b074b7bbSAlexander V. Chernikov * Refs found object, allocate new index for non-existing object. 14129490a627SAlexander V. Chernikov * Fills in @oib with userland/kernel indexes. 14139490a627SAlexander V. Chernikov * First free oidx pointer is saved back in @oib. 1414b074b7bbSAlexander V. Chernikov * 1415b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1416b074b7bbSAlexander V. Chernikov */ 1417b074b7bbSAlexander V. Chernikov static int 14189490a627SAlexander V. Chernikov bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule, 14199490a627SAlexander V. Chernikov struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti) 1420b074b7bbSAlexander V. Chernikov { 1421b074b7bbSAlexander V. Chernikov struct table_config *tc; 14229490a627SAlexander V. Chernikov struct namedobj_instance *ni; 14239490a627SAlexander V. Chernikov struct named_object *no; 14249490a627SAlexander V. Chernikov int error, l, cmdlen; 14259490a627SAlexander V. Chernikov ipfw_insn *cmd; 14269490a627SAlexander V. Chernikov struct obj_idx *pidx, *p; 14279490a627SAlexander V. Chernikov 14289490a627SAlexander V. Chernikov pidx = *oib; 14299490a627SAlexander V. Chernikov l = rule->cmd_len; 14309490a627SAlexander V. Chernikov cmd = rule->cmd; 14319490a627SAlexander V. Chernikov cmdlen = 0; 14329490a627SAlexander V. Chernikov error = 0; 14339490a627SAlexander V. Chernikov 14349490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 14359490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 14369490a627SAlexander V. Chernikov 14379490a627SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 14389490a627SAlexander V. Chernikov cmdlen = F_LEN(cmd); 14399490a627SAlexander V. Chernikov 14409490a627SAlexander V. Chernikov if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0) 14419490a627SAlexander V. Chernikov continue; 1442b074b7bbSAlexander V. Chernikov 1443b074b7bbSAlexander V. Chernikov pidx->uidx = ti->uidx; 1444b074b7bbSAlexander V. Chernikov pidx->type = ti->type; 1445b074b7bbSAlexander V. Chernikov 14469490a627SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 14479490a627SAlexander V. Chernikov if (tc->no.type != ti->type) { 14489490a627SAlexander V. Chernikov /* Incompatible types */ 14499490a627SAlexander V. Chernikov error = EINVAL; 14509490a627SAlexander V. Chernikov break; 14519490a627SAlexander V. Chernikov } 14529f7d47b0SAlexander V. Chernikov 14539490a627SAlexander V. Chernikov /* Reference found table and save kidx */ 14549490a627SAlexander V. Chernikov tc->no.refcnt++; 14559490a627SAlexander V. Chernikov pidx->kidx = tc->no.kidx; 14569490a627SAlexander V. Chernikov pidx++; 14579490a627SAlexander V. Chernikov continue; 14589490a627SAlexander V. Chernikov } 14599490a627SAlexander V. Chernikov 14609490a627SAlexander V. Chernikov /* Table not found. Allocate new index and save for later */ 1461b074b7bbSAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, ti->set, &pidx->kidx) != 0) { 1462b074b7bbSAlexander V. Chernikov printf("Unable to allocate table index in set %u." 1463b074b7bbSAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 1464b074b7bbSAlexander V. Chernikov ti->set); 14659490a627SAlexander V. Chernikov error = EBUSY; 14669490a627SAlexander V. Chernikov break; 1467b074b7bbSAlexander V. Chernikov } 1468b074b7bbSAlexander V. Chernikov 1469b074b7bbSAlexander V. Chernikov ci->new_tables++; 14709490a627SAlexander V. Chernikov pidx->new = 1; 14719490a627SAlexander V. Chernikov pidx++; 1472b074b7bbSAlexander V. Chernikov } 1473b074b7bbSAlexander V. Chernikov 14749490a627SAlexander V. Chernikov if (error != 0) { 14759490a627SAlexander V. Chernikov /* Unref everything we have already done */ 14769490a627SAlexander V. Chernikov for (p = *oib; p < pidx; p++) { 14779490a627SAlexander V. Chernikov if (p->new != 0) { 14789490a627SAlexander V. Chernikov ipfw_objhash_free_idx(ni, ci->tableset,p->kidx); 14799490a627SAlexander V. Chernikov continue; 14809490a627SAlexander V. Chernikov } 1481b074b7bbSAlexander V. Chernikov 14829490a627SAlexander V. Chernikov /* Find & unref by existing idx */ 14839490a627SAlexander V. Chernikov no = ipfw_objhash_lookup_idx(ni, ci->tableset, p->kidx); 14849490a627SAlexander V. Chernikov KASSERT(no != NULL, ("Ref'd table %d disappeared", 14859490a627SAlexander V. Chernikov p->kidx)); 1486b074b7bbSAlexander V. Chernikov 14879490a627SAlexander V. Chernikov no->refcnt--; 14889490a627SAlexander V. Chernikov } 14899490a627SAlexander V. Chernikov } 14909490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1491b074b7bbSAlexander V. Chernikov 14929490a627SAlexander V. Chernikov *oib = pidx; 14939490a627SAlexander V. Chernikov 14949490a627SAlexander V. Chernikov return (error); 1495b074b7bbSAlexander V. Chernikov } 1496b074b7bbSAlexander V. Chernikov 1497b074b7bbSAlexander V. Chernikov /* 1498b074b7bbSAlexander V. Chernikov * Compatibility function for old ipfw(8) binaries. 1499b074b7bbSAlexander V. Chernikov * Rewrites table kernel indices with userland ones. 1500b074b7bbSAlexander V. Chernikov * Works for \d+ talbes only (e.g. for tables, converted 1501b074b7bbSAlexander V. Chernikov * from old numbered system calls). 1502b074b7bbSAlexander V. Chernikov * 1503b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1504b074b7bbSAlexander V. Chernikov * Raises error on any other tables. 1505b074b7bbSAlexander V. Chernikov */ 1506b074b7bbSAlexander V. Chernikov int 1507b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule) 1508b074b7bbSAlexander V. Chernikov { 1509b074b7bbSAlexander V. Chernikov int cmdlen, l; 1510b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1511b074b7bbSAlexander V. Chernikov uint32_t set; 1512b074b7bbSAlexander V. Chernikov uint16_t kidx; 1513b074b7bbSAlexander V. Chernikov uint8_t type; 1514b074b7bbSAlexander V. Chernikov struct named_object *no; 1515b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1516b074b7bbSAlexander V. Chernikov 1517b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1518b074b7bbSAlexander V. Chernikov 1519b074b7bbSAlexander V. Chernikov set = TABLE_SET(rule->set); 1520b074b7bbSAlexander V. Chernikov 1521b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1522b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1523b074b7bbSAlexander V. Chernikov cmdlen = 0; 1524b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1525b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1526b074b7bbSAlexander V. Chernikov 1527b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1528b074b7bbSAlexander V. Chernikov continue; 1529b074b7bbSAlexander V. Chernikov 1530b074b7bbSAlexander V. Chernikov if ((no = ipfw_objhash_lookup_idx(ni, set, kidx)) == NULL) 1531b074b7bbSAlexander V. Chernikov return (1); 1532b074b7bbSAlexander V. Chernikov 1533b074b7bbSAlexander V. Chernikov if (no->compat == 0) 1534b074b7bbSAlexander V. Chernikov return (2); 1535b074b7bbSAlexander V. Chernikov 1536b074b7bbSAlexander V. Chernikov update_table_opcode(cmd, no->uidx); 1537b074b7bbSAlexander V. Chernikov } 1538b074b7bbSAlexander V. Chernikov 1539b074b7bbSAlexander V. Chernikov return (0); 1540b074b7bbSAlexander V. Chernikov } 1541b074b7bbSAlexander V. Chernikov 1542563b5ab1SAlexander V. Chernikov /* 1543563b5ab1SAlexander V. Chernikov * Sets every table kidx in @bmask which is used in rule @rule. 1544563b5ab1SAlexander V. Chernikov * 1545563b5ab1SAlexander V. Chernikov * Returns number of newly-referenced tables. 1546563b5ab1SAlexander V. Chernikov */ 1547563b5ab1SAlexander V. Chernikov int 1548563b5ab1SAlexander V. Chernikov ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule, 1549563b5ab1SAlexander V. Chernikov uint32_t *bmask) 1550563b5ab1SAlexander V. Chernikov { 1551563b5ab1SAlexander V. Chernikov int cmdlen, l, count; 1552563b5ab1SAlexander V. Chernikov ipfw_insn *cmd; 1553563b5ab1SAlexander V. Chernikov uint16_t kidx; 1554563b5ab1SAlexander V. Chernikov uint8_t type; 1555563b5ab1SAlexander V. Chernikov 1556563b5ab1SAlexander V. Chernikov l = rule->cmd_len; 1557563b5ab1SAlexander V. Chernikov cmd = rule->cmd; 1558563b5ab1SAlexander V. Chernikov cmdlen = 0; 1559563b5ab1SAlexander V. Chernikov count = 0; 1560563b5ab1SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1561563b5ab1SAlexander V. Chernikov cmdlen = F_LEN(cmd); 1562563b5ab1SAlexander V. Chernikov 1563563b5ab1SAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1564563b5ab1SAlexander V. Chernikov continue; 1565563b5ab1SAlexander V. Chernikov 1566563b5ab1SAlexander V. Chernikov if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0) 1567563b5ab1SAlexander V. Chernikov count++; 1568563b5ab1SAlexander V. Chernikov 1569563b5ab1SAlexander V. Chernikov bmask[kidx / 32] |= 1 << (kidx % 32); 1570563b5ab1SAlexander V. Chernikov } 1571563b5ab1SAlexander V. Chernikov 1572563b5ab1SAlexander V. Chernikov return (count); 1573563b5ab1SAlexander V. Chernikov } 1574563b5ab1SAlexander V. Chernikov 1575563b5ab1SAlexander V. Chernikov 1576b074b7bbSAlexander V. Chernikov 1577b074b7bbSAlexander V. Chernikov /* 1578b074b7bbSAlexander V. Chernikov * Checks is opcode is referencing table of appropriate type. 1579b074b7bbSAlexander V. Chernikov * Adds reference count for found table if true. 1580b074b7bbSAlexander V. Chernikov * Rewrites user-supplied opcode values with kernel ones. 1581b074b7bbSAlexander V. Chernikov * 1582b074b7bbSAlexander V. Chernikov * Returns 0 on success and appropriate error code otherwise. 1583b074b7bbSAlexander V. Chernikov */ 1584b074b7bbSAlexander V. Chernikov int 1585b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, 1586b074b7bbSAlexander V. Chernikov struct rule_check_info *ci) 1587b074b7bbSAlexander V. Chernikov { 1588b074b7bbSAlexander V. Chernikov int cmdlen, error, ftype, l; 1589b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1590b074b7bbSAlexander V. Chernikov uint16_t uidx; 1591b074b7bbSAlexander V. Chernikov uint8_t type; 1592b074b7bbSAlexander V. Chernikov struct table_config *tc; 15939f7d47b0SAlexander V. Chernikov struct table_algo *ta; 1594b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1595b074b7bbSAlexander V. Chernikov struct named_object *no, *no_n, *no_tmp; 15969490a627SAlexander V. Chernikov struct obj_idx *p, *pidx_first, *pidx_last; 1597b074b7bbSAlexander V. Chernikov struct namedobjects_head nh; 1598b074b7bbSAlexander V. Chernikov struct tid_info ti; 1599b074b7bbSAlexander V. Chernikov 1600b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1601b074b7bbSAlexander V. Chernikov 16029490a627SAlexander V. Chernikov /* Prepare queue to store configs */ 16039490a627SAlexander V. Chernikov TAILQ_INIT(&nh); 16049490a627SAlexander V. Chernikov 1605b074b7bbSAlexander V. Chernikov /* 1606b074b7bbSAlexander V. Chernikov * Prepare an array for storing opcode indices. 1607b074b7bbSAlexander V. Chernikov * Use stack allocation by default. 1608b074b7bbSAlexander V. Chernikov */ 1609b074b7bbSAlexander V. Chernikov if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 1610b074b7bbSAlexander V. Chernikov /* Stack */ 16119490a627SAlexander V. Chernikov pidx_first = ci->obuf; 1612b074b7bbSAlexander V. Chernikov } else 16139490a627SAlexander V. Chernikov pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx), 1614b074b7bbSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1615b074b7bbSAlexander V. Chernikov 16169490a627SAlexander V. Chernikov pidx_last = pidx_first; 1617b074b7bbSAlexander V. Chernikov error = 0; 1618b074b7bbSAlexander V. Chernikov 1619b074b7bbSAlexander V. Chernikov type = 0; 1620b074b7bbSAlexander V. Chernikov ftype = 0; 1621b074b7bbSAlexander V. Chernikov 1622b074b7bbSAlexander V. Chernikov ci->tableset = TABLE_SET(ci->krule->set); 1623b074b7bbSAlexander V. Chernikov 1624b074b7bbSAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 1625b074b7bbSAlexander V. Chernikov ti.set = ci->tableset; 1626b074b7bbSAlexander V. Chernikov ti.tlvs = ci->tlvs; 1627b074b7bbSAlexander V. Chernikov ti.tlen = ci->tlen; 1628b074b7bbSAlexander V. Chernikov 1629b074b7bbSAlexander V. Chernikov /* 16309490a627SAlexander V. Chernikov * Stage 1: reference existing tables, determine number 16319490a627SAlexander V. Chernikov * of tables we need to allocate and allocate indexes for each. 1632b074b7bbSAlexander V. Chernikov */ 16339490a627SAlexander V. Chernikov error = bind_table_rule(chain, ci->krule, ci, &pidx_last, &ti); 1634b074b7bbSAlexander V. Chernikov 1635b074b7bbSAlexander V. Chernikov if (error != 0) { 16369490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 16379490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 1638b074b7bbSAlexander V. Chernikov 1639b074b7bbSAlexander V. Chernikov return (error); 1640b074b7bbSAlexander V. Chernikov } 1641b074b7bbSAlexander V. Chernikov 1642b074b7bbSAlexander V. Chernikov /* 1643b074b7bbSAlexander V. Chernikov * Stage 2: allocate table configs for every non-existent table 1644b074b7bbSAlexander V. Chernikov */ 1645b074b7bbSAlexander V. Chernikov 16469f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 16479490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 1648b074b7bbSAlexander V. Chernikov if (p->new == 0) 1649b074b7bbSAlexander V. Chernikov continue; 1650b074b7bbSAlexander V. Chernikov 1651b074b7bbSAlexander V. Chernikov /* TODO: get name from TLV */ 1652b074b7bbSAlexander V. Chernikov ti.uidx = p->uidx; 1653b074b7bbSAlexander V. Chernikov ti.type = p->type; 16549f7d47b0SAlexander V. Chernikov ti.atype = 0; 1655b074b7bbSAlexander V. Chernikov 16569490a627SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti, NULL); 16579f7d47b0SAlexander V. Chernikov if (ta == NULL) { 16589f7d47b0SAlexander V. Chernikov error = ENOTSUP; 16599f7d47b0SAlexander V. Chernikov goto free; 16609f7d47b0SAlexander V. Chernikov } 16619490a627SAlexander V. Chernikov tc = alloc_table_config(ni, &ti, ta, NULL); 1662b074b7bbSAlexander V. Chernikov 1663b074b7bbSAlexander V. Chernikov if (tc == NULL) { 1664b074b7bbSAlexander V. Chernikov error = ENOMEM; 1665b074b7bbSAlexander V. Chernikov goto free; 1666b074b7bbSAlexander V. Chernikov } 1667b074b7bbSAlexander V. Chernikov 1668b074b7bbSAlexander V. Chernikov tc->no.kidx = p->kidx; 1669b074b7bbSAlexander V. Chernikov tc->no.refcnt = 1; 1670b074b7bbSAlexander V. Chernikov 1671b074b7bbSAlexander V. Chernikov /* Add to list */ 1672b074b7bbSAlexander V. Chernikov TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next); 1673b074b7bbSAlexander V. Chernikov } 1674b074b7bbSAlexander V. Chernikov 1675b074b7bbSAlexander V. Chernikov /* 1676b074b7bbSAlexander V. Chernikov * Stage 2.1: Check if we're going to create 2 tables 1677b074b7bbSAlexander V. Chernikov * with the same name, but different table types. 1678b074b7bbSAlexander V. Chernikov */ 1679b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no, &nh, nn_next) { 1680b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no_tmp, &nh, nn_next) { 16819490a627SAlexander V. Chernikov if (ipfw_objhash_same_name(ni, no, no_tmp) == 0) 1682b074b7bbSAlexander V. Chernikov continue; 1683b074b7bbSAlexander V. Chernikov if (no->type != no_tmp->type) { 1684b074b7bbSAlexander V. Chernikov error = EINVAL; 1685b074b7bbSAlexander V. Chernikov goto free; 1686b074b7bbSAlexander V. Chernikov } 1687b074b7bbSAlexander V. Chernikov } 1688b074b7bbSAlexander V. Chernikov } 16899f7d47b0SAlexander V. Chernikov } 1690b074b7bbSAlexander V. Chernikov 16919f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 16929f7d47b0SAlexander V. Chernikov 16939f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 1694b074b7bbSAlexander V. Chernikov /* 1695b074b7bbSAlexander V. Chernikov * Stage 3: link & reference new table configs 1696b074b7bbSAlexander V. Chernikov */ 1697b074b7bbSAlexander V. Chernikov 1698b074b7bbSAlexander V. Chernikov 1699b074b7bbSAlexander V. Chernikov /* 1700b074b7bbSAlexander V. Chernikov * Step 3.1: Check if some tables we need to create have been 1701b074b7bbSAlexander V. Chernikov * already created with different table type. 1702b074b7bbSAlexander V. Chernikov */ 1703b074b7bbSAlexander V. Chernikov 1704b074b7bbSAlexander V. Chernikov error = 0; 1705b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1706b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1707b074b7bbSAlexander V. Chernikov if (no_n == NULL) 1708b074b7bbSAlexander V. Chernikov continue; 1709b074b7bbSAlexander V. Chernikov 1710b074b7bbSAlexander V. Chernikov if (no_n->type != no->type) { 1711b074b7bbSAlexander V. Chernikov error = EINVAL; 1712b074b7bbSAlexander V. Chernikov break; 1713b074b7bbSAlexander V. Chernikov } 1714b074b7bbSAlexander V. Chernikov 1715b074b7bbSAlexander V. Chernikov } 1716b074b7bbSAlexander V. Chernikov 1717b074b7bbSAlexander V. Chernikov if (error != 0) { 1718b074b7bbSAlexander V. Chernikov /* 1719b074b7bbSAlexander V. Chernikov * Someone has allocated table with different table type. 1720b074b7bbSAlexander V. Chernikov * We have to rollback everything. 1721b074b7bbSAlexander V. Chernikov */ 1722b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1723b074b7bbSAlexander V. Chernikov goto free; 1724b074b7bbSAlexander V. Chernikov } 1725b074b7bbSAlexander V. Chernikov 1726b074b7bbSAlexander V. Chernikov 1727b074b7bbSAlexander V. Chernikov /* 17289f7d47b0SAlexander V. Chernikov * Attach new tables. 17299f7d47b0SAlexander V. Chernikov * We need to set table pointers for each new table, 1730b074b7bbSAlexander V. Chernikov * so we have to acquire main WLOCK. 1731b074b7bbSAlexander V. Chernikov */ 1732b074b7bbSAlexander V. Chernikov IPFW_WLOCK(chain); 1733b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1734b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1735b074b7bbSAlexander V. Chernikov 17369490a627SAlexander V. Chernikov if (no_n == NULL) { 17379490a627SAlexander V. Chernikov /* New table. Attach to runtime hash */ 17389490a627SAlexander V. Chernikov TAILQ_REMOVE(&nh, no, nn_next); 17399490a627SAlexander V. Chernikov link_table(chain, (struct table_config *)no); 1740b074b7bbSAlexander V. Chernikov continue; 1741b074b7bbSAlexander V. Chernikov } 1742b074b7bbSAlexander V. Chernikov 17439490a627SAlexander V. Chernikov /* 17449490a627SAlexander V. Chernikov * Newly-allocated table with the same type. 17459490a627SAlexander V. Chernikov * Reference it and update out @pidx array 17469490a627SAlexander V. Chernikov * rewrite info. 17479490a627SAlexander V. Chernikov */ 17489490a627SAlexander V. Chernikov no_n->refcnt++; 17499490a627SAlexander V. Chernikov /* Keep oib array in sync: update kidx */ 17509490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 17519490a627SAlexander V. Chernikov if (p->kidx != no->kidx) 17529490a627SAlexander V. Chernikov continue; 17539490a627SAlexander V. Chernikov /* Update kidx */ 17549490a627SAlexander V. Chernikov p->kidx = no_n->kidx; 17559490a627SAlexander V. Chernikov break; 17569490a627SAlexander V. Chernikov } 1757b074b7bbSAlexander V. Chernikov } 1758b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(chain); 17599f7d47b0SAlexander V. Chernikov } 1760b074b7bbSAlexander V. Chernikov 1761b074b7bbSAlexander V. Chernikov /* Perform rule rewrite */ 1762b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 1763b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 1764b074b7bbSAlexander V. Chernikov cmdlen = 0; 17659490a627SAlexander V. Chernikov p = pidx_first; 1766b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1767b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1768b074b7bbSAlexander V. Chernikov 1769b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &uidx, &type) != 0) 1770b074b7bbSAlexander V. Chernikov continue; 17719490a627SAlexander V. Chernikov update_table_opcode(cmd, p->kidx); 17729490a627SAlexander V. Chernikov p++; 1773b074b7bbSAlexander V. Chernikov } 1774b074b7bbSAlexander V. Chernikov 1775b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1776b074b7bbSAlexander V. Chernikov 1777b074b7bbSAlexander V. Chernikov error = 0; 1778b074b7bbSAlexander V. Chernikov 1779b074b7bbSAlexander V. Chernikov /* 1780b074b7bbSAlexander V. Chernikov * Stage 4: free resources 1781b074b7bbSAlexander V. Chernikov */ 1782b074b7bbSAlexander V. Chernikov free: 17839490a627SAlexander V. Chernikov if (!TAILQ_EMPTY(&nh)) { 17849490a627SAlexander V. Chernikov /* Free indexes first */ 17859490a627SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 17869490a627SAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 17879490a627SAlexander V. Chernikov ipfw_objhash_free_idx(ni, ci->tableset, no->kidx); 17889490a627SAlexander V. Chernikov } 17899490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 17909490a627SAlexander V. Chernikov /* Free configs */ 1791b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) 1792b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 17939490a627SAlexander V. Chernikov } 1794b074b7bbSAlexander V. Chernikov 17959490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 17969490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 1797b074b7bbSAlexander V. Chernikov 1798b074b7bbSAlexander V. Chernikov return (error); 1799b074b7bbSAlexander V. Chernikov } 1800b074b7bbSAlexander V. Chernikov 1801b074b7bbSAlexander V. Chernikov /* 1802b074b7bbSAlexander V. Chernikov * Remove references from every table used in @rule. 1803b074b7bbSAlexander V. Chernikov */ 1804b074b7bbSAlexander V. Chernikov void 1805b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule) 1806b074b7bbSAlexander V. Chernikov { 1807b074b7bbSAlexander V. Chernikov int cmdlen, l; 1808b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1809b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1810b074b7bbSAlexander V. Chernikov struct named_object *no; 1811b074b7bbSAlexander V. Chernikov uint32_t set; 1812b074b7bbSAlexander V. Chernikov uint16_t kidx; 1813b074b7bbSAlexander V. Chernikov uint8_t type; 1814b074b7bbSAlexander V. Chernikov 1815b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1816b074b7bbSAlexander V. Chernikov 1817b074b7bbSAlexander V. Chernikov set = TABLE_SET(rule->set); 1818b074b7bbSAlexander V. Chernikov 1819b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1820b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1821b074b7bbSAlexander V. Chernikov cmdlen = 0; 1822b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1823b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1824b074b7bbSAlexander V. Chernikov 1825b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1826b074b7bbSAlexander V. Chernikov continue; 1827b074b7bbSAlexander V. Chernikov 1828b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_idx(ni, set, kidx); 1829b074b7bbSAlexander V. Chernikov 1830b074b7bbSAlexander V. Chernikov KASSERT(no != NULL, ("table id %d not found", kidx)); 1831b074b7bbSAlexander V. Chernikov KASSERT(no->type == type, ("wrong type %d (%d) for table id %d", 1832b074b7bbSAlexander V. Chernikov no->type, type, kidx)); 1833b074b7bbSAlexander V. Chernikov KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 1834b074b7bbSAlexander V. Chernikov kidx, no->refcnt)); 1835b074b7bbSAlexander V. Chernikov 1836b074b7bbSAlexander V. Chernikov no->refcnt--; 1837b074b7bbSAlexander V. Chernikov } 1838b074b7bbSAlexander V. Chernikov } 1839b074b7bbSAlexander V. Chernikov 1840b074b7bbSAlexander V. Chernikov 1841b074b7bbSAlexander V. Chernikov /* 1842b074b7bbSAlexander V. Chernikov * Removes table bindings for every rule in rule chain @head. 1843b074b7bbSAlexander V. Chernikov */ 1844b074b7bbSAlexander V. Chernikov void 1845b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head) 1846b074b7bbSAlexander V. Chernikov { 1847b074b7bbSAlexander V. Chernikov struct ip_fw *rule; 1848b074b7bbSAlexander V. Chernikov 1849b074b7bbSAlexander V. Chernikov while ((rule = head) != NULL) { 1850b074b7bbSAlexander V. Chernikov head = head->x_next; 1851b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(chain, rule); 1852b074b7bbSAlexander V. Chernikov } 1853b074b7bbSAlexander V. Chernikov } 1854b074b7bbSAlexander V. Chernikov 1855b074b7bbSAlexander V. Chernikov 18563b3a8eb9SGleb Smirnoff /* end of file */ 1857