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 /* 303b3a8eb9SGleb Smirnoff * Lookup table support for ipfw 313b3a8eb9SGleb Smirnoff * 323b3a8eb9SGleb Smirnoff * Lookup tables are implemented (at the moment) using the radix 333b3a8eb9SGleb Smirnoff * tree used for routing tables. Tables store key-value entries, where 343b3a8eb9SGleb Smirnoff * keys are network prefixes (addr/masklen), and values are integers. 353b3a8eb9SGleb Smirnoff * As a degenerate case we can interpret keys as 32-bit integers 363b3a8eb9SGleb Smirnoff * (with a /32 mask). 373b3a8eb9SGleb Smirnoff * 383b3a8eb9SGleb Smirnoff * The table is protected by the IPFW lock even for manipulation coming 393b3a8eb9SGleb Smirnoff * from userland, because operations are typically fast. 403b3a8eb9SGleb Smirnoff */ 413b3a8eb9SGleb Smirnoff 423b3a8eb9SGleb Smirnoff #include "opt_ipfw.h" 433b3a8eb9SGleb Smirnoff #include "opt_inet.h" 443b3a8eb9SGleb Smirnoff #ifndef INET 453b3a8eb9SGleb Smirnoff #error IPFIREWALL requires INET. 463b3a8eb9SGleb Smirnoff #endif /* INET */ 473b3a8eb9SGleb Smirnoff #include "opt_inet6.h" 483b3a8eb9SGleb Smirnoff 493b3a8eb9SGleb Smirnoff #include <sys/param.h> 503b3a8eb9SGleb Smirnoff #include <sys/systm.h> 513b3a8eb9SGleb Smirnoff #include <sys/malloc.h> 523b3a8eb9SGleb Smirnoff #include <sys/kernel.h> 533b3a8eb9SGleb Smirnoff #include <sys/lock.h> 543b3a8eb9SGleb Smirnoff #include <sys/rwlock.h> 553b3a8eb9SGleb Smirnoff #include <sys/socket.h> 563b3a8eb9SGleb Smirnoff #include <sys/queue.h> 573b3a8eb9SGleb Smirnoff #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 583b3a8eb9SGleb Smirnoff #include <net/radix.h> 593b3a8eb9SGleb Smirnoff #include <net/route.h> 603b3a8eb9SGleb Smirnoff #include <net/vnet.h> 613b3a8eb9SGleb Smirnoff 623b3a8eb9SGleb Smirnoff #include <netinet/in.h> 633b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 643b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h> 653b3a8eb9SGleb Smirnoff 663b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h> 673b3a8eb9SGleb Smirnoff 683b3a8eb9SGleb Smirnoff 693b3a8eb9SGleb Smirnoff /* 70b074b7bbSAlexander V. Chernikov * Table has the following `type` concepts: 71b074b7bbSAlexander V. Chernikov * 729f7d47b0SAlexander V. Chernikov * `no.type` represents lookup key type (cidr, ifp, uid, etc..) 739f7d47b0SAlexander V. Chernikov * `ta->atype` represents exact lookup algorithm. 74b074b7bbSAlexander V. Chernikov * For example, we can use more efficient search schemes if we plan 75b074b7bbSAlexander V. Chernikov * to use some specific table for storing host-routes only. 769f7d47b0SAlexander V. Chernikov * `ftype` is pure userland field helping to properly format table data 779f7d47b0SAlexander V. Chernikov * e.g. "value is IPv4 nexthop" or "key is port number" 78b074b7bbSAlexander V. Chernikov * 79b074b7bbSAlexander V. Chernikov */ 80b074b7bbSAlexander V. Chernikov struct table_config { 81b074b7bbSAlexander V. Chernikov struct named_object no; 82b074b7bbSAlexander V. Chernikov uint8_t ftype; /* format table type */ 83b074b7bbSAlexander V. Chernikov uint8_t linked; /* 1 if already linked */ 849f7d47b0SAlexander V. Chernikov uint16_t spare0; 85b074b7bbSAlexander V. Chernikov uint32_t count; /* Number of records */ 86b074b7bbSAlexander V. Chernikov char tablename[64]; /* table name */ 879f7d47b0SAlexander V. Chernikov struct table_algo *ta; /* Callbacks for given algo */ 889f7d47b0SAlexander V. Chernikov void *astate; /* algorithm state */ 899f7d47b0SAlexander V. Chernikov struct table_info ti; /* data to put to table_info */ 90b074b7bbSAlexander V. Chernikov }; 91b074b7bbSAlexander V. Chernikov #define TABLE_SET(set) ((V_fw_tables_sets != 0) ? set : 0) 92b074b7bbSAlexander V. Chernikov 93b074b7bbSAlexander V. Chernikov struct tables_config { 94b074b7bbSAlexander V. Chernikov struct namedobj_instance *namehash; 959f7d47b0SAlexander V. Chernikov int algo_count; 969f7d47b0SAlexander V. Chernikov struct table_algo *algo[256]; 97b074b7bbSAlexander V. Chernikov }; 98b074b7bbSAlexander V. Chernikov 99b074b7bbSAlexander V. Chernikov static struct table_config *find_table(struct namedobj_instance *ni, 100b074b7bbSAlexander V. Chernikov struct tid_info *ti); 101b074b7bbSAlexander V. Chernikov static struct table_config *alloc_table_config(struct namedobj_instance *ni, 1029f7d47b0SAlexander V. Chernikov struct tid_info *ti, struct table_algo *ta); 103b074b7bbSAlexander V. Chernikov static void free_table_config(struct namedobj_instance *ni, 104b074b7bbSAlexander V. Chernikov struct table_config *tc); 105b074b7bbSAlexander V. Chernikov static void link_table(struct ip_fw_chain *chain, struct table_config *tc); 106b074b7bbSAlexander V. Chernikov static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc); 107b074b7bbSAlexander V. Chernikov static void free_table_state(void **state, void **xstate, uint8_t type); 108b074b7bbSAlexander V. Chernikov 1099f7d47b0SAlexander V. Chernikov static struct table_algo *find_table_algo(struct tables_config *tableconf, 1109f7d47b0SAlexander V. Chernikov struct tid_info *ti); 111b074b7bbSAlexander V. Chernikov 112b074b7bbSAlexander V. Chernikov #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) 113b074b7bbSAlexander V. Chernikov #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) 1149f7d47b0SAlexander V. Chernikov #define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) 115b074b7bbSAlexander V. Chernikov 116b074b7bbSAlexander V. Chernikov 1173b3a8eb9SGleb Smirnoff 1183b3a8eb9SGleb Smirnoff int 119b074b7bbSAlexander V. Chernikov ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 120b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 1213b3a8eb9SGleb Smirnoff { 122b074b7bbSAlexander V. Chernikov struct table_config *tc, *tc_new; 1239f7d47b0SAlexander V. Chernikov struct table_algo *ta; 124b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 125b074b7bbSAlexander V. Chernikov uint16_t kidx; 1269f7d47b0SAlexander V. Chernikov int error; 1279f7d47b0SAlexander V. Chernikov char ta_buf[128]; 1283b3a8eb9SGleb Smirnoff 1299f7d47b0SAlexander V. Chernikov #if 0 130b074b7bbSAlexander V. Chernikov if (ti->uidx >= V_fw_tables_max) 1313b3a8eb9SGleb Smirnoff return (EINVAL); 1323b3a8eb9SGleb Smirnoff #endif 1339f7d47b0SAlexander V. Chernikov 1349f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1359f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1369f7d47b0SAlexander V. Chernikov 1379f7d47b0SAlexander V. Chernikov /* 1389f7d47b0SAlexander V. Chernikov * Find and reference existing table. 1399f7d47b0SAlexander V. Chernikov */ 1409f7d47b0SAlexander V. Chernikov ta = NULL; 1419f7d47b0SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1429f7d47b0SAlexander V. Chernikov /* check table type */ 1439f7d47b0SAlexander V. Chernikov if (tc->no.type != ti->type) { 1449f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1453b3a8eb9SGleb Smirnoff return (EINVAL); 1463b3a8eb9SGleb Smirnoff } 1473b3a8eb9SGleb Smirnoff 1489f7d47b0SAlexander V. Chernikov /* Reference and unlock */ 1499f7d47b0SAlexander V. Chernikov tc->no.refcnt++; 1509f7d47b0SAlexander V. Chernikov ta = tc->ta; 1519f7d47b0SAlexander V. Chernikov } 1529f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1533b3a8eb9SGleb Smirnoff 1549f7d47b0SAlexander V. Chernikov tc_new = NULL; 1559f7d47b0SAlexander V. Chernikov if (ta == NULL) { 1569f7d47b0SAlexander V. Chernikov /* Table not found. We have to create new one */ 1579f7d47b0SAlexander V. Chernikov if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti)) == NULL) 1589f7d47b0SAlexander V. Chernikov return (ENOTSUP); 1593b3a8eb9SGleb Smirnoff 1609f7d47b0SAlexander V. Chernikov tc_new = alloc_table_config(ni, ti, ta); 1619f7d47b0SAlexander V. Chernikov if (tc_new == NULL) 1629f7d47b0SAlexander V. Chernikov return (ENOMEM); 1639f7d47b0SAlexander V. Chernikov } 1643b3a8eb9SGleb Smirnoff 1659f7d47b0SAlexander V. Chernikov /* Prepare record (allocate memory) */ 1669f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 1679f7d47b0SAlexander V. Chernikov error = ta->prepare_add(tei, &ta_buf); 1689f7d47b0SAlexander V. Chernikov if (error != 0) { 1699f7d47b0SAlexander V. Chernikov if (tc_new != NULL) 1709f7d47b0SAlexander V. Chernikov free_table_config(ni, tc_new); 1719f7d47b0SAlexander V. Chernikov return (error); 1723b3a8eb9SGleb Smirnoff } 1733b3a8eb9SGleb Smirnoff 174b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1753b3a8eb9SGleb Smirnoff 176b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1773b3a8eb9SGleb Smirnoff 1789f7d47b0SAlexander V. Chernikov if (tc == NULL) { 1799f7d47b0SAlexander V. Chernikov /* Check if another table was allocated by other thread */ 180b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1819f7d47b0SAlexander V. Chernikov 1829f7d47b0SAlexander V. Chernikov /* 1839f7d47b0SAlexander V. Chernikov * Check if algoritm is the same since we've 1849f7d47b0SAlexander V. Chernikov * already allocated state using @ta algoritm 1859f7d47b0SAlexander V. Chernikov * callbacks. 1869f7d47b0SAlexander V. Chernikov */ 1879f7d47b0SAlexander V. Chernikov if (tc->ta != ta) { 188b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 189b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 1903b3a8eb9SGleb Smirnoff return (EINVAL); 1913b3a8eb9SGleb Smirnoff } 1923b3a8eb9SGleb Smirnoff } else { 1933b3a8eb9SGleb Smirnoff /* 1949f7d47b0SAlexander V. Chernikov * We're first to create this table. 195b074b7bbSAlexander V. Chernikov * Set tc_new to zero not to free it afterwards. 1963b3a8eb9SGleb Smirnoff */ 197b074b7bbSAlexander V. Chernikov tc = tc_new; 198b074b7bbSAlexander V. Chernikov tc_new = NULL; 199b074b7bbSAlexander V. Chernikov 200b074b7bbSAlexander V. Chernikov /* Allocate table index. */ 201b074b7bbSAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, ti->set, &kidx) != 0) { 202b074b7bbSAlexander V. Chernikov /* Index full. */ 203b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 204b074b7bbSAlexander V. Chernikov printf("Unable to allocate index for table %s." 205b074b7bbSAlexander V. Chernikov " Consider increasing " 206b074b7bbSAlexander V. Chernikov "net.inet.ip.fw.tables_max", 207b074b7bbSAlexander V. Chernikov tc->no.name); 208b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 209b074b7bbSAlexander V. Chernikov return (EBUSY); 2103b3a8eb9SGleb Smirnoff } 211b074b7bbSAlexander V. Chernikov /* Save kidx */ 212b074b7bbSAlexander V. Chernikov tc->no.kidx = kidx; 213b074b7bbSAlexander V. Chernikov } 214b074b7bbSAlexander V. Chernikov } else { 2159f7d47b0SAlexander V. Chernikov /* Drop reference we've used in first search */ 2169f7d47b0SAlexander V. Chernikov tc->no.refcnt--; 217b074b7bbSAlexander V. Chernikov } 218b074b7bbSAlexander V. Chernikov 219b074b7bbSAlexander V. Chernikov /* We've got valid table in @tc. Let's add data */ 2209f7d47b0SAlexander V. Chernikov kidx = tc->no.kidx; 2219f7d47b0SAlexander V. Chernikov ta = tc->ta; 2229f7d47b0SAlexander V. Chernikov 223b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 224b074b7bbSAlexander V. Chernikov 225b074b7bbSAlexander V. Chernikov if (tc->linked == 0) { 226b074b7bbSAlexander V. Chernikov link_table(ch, tc); 227b074b7bbSAlexander V. Chernikov } 228b074b7bbSAlexander V. Chernikov 2299f7d47b0SAlexander V. Chernikov error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); 2303b3a8eb9SGleb Smirnoff 2313b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2329f7d47b0SAlexander V. Chernikov 2339f7d47b0SAlexander V. Chernikov if (error == 0) 2349f7d47b0SAlexander V. Chernikov tc->count++; 2359f7d47b0SAlexander V. Chernikov 236b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 237b074b7bbSAlexander V. Chernikov 238b074b7bbSAlexander V. Chernikov if (tc_new != NULL) 239b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 2403b3a8eb9SGleb Smirnoff 2419f7d47b0SAlexander V. Chernikov if (error != 0) 2429f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 243b074b7bbSAlexander V. Chernikov 2449f7d47b0SAlexander V. Chernikov return (error); 2453b3a8eb9SGleb Smirnoff } 2463b3a8eb9SGleb Smirnoff 2473b3a8eb9SGleb Smirnoff int 248b074b7bbSAlexander V. Chernikov ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 249b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 2503b3a8eb9SGleb Smirnoff { 251b074b7bbSAlexander V. Chernikov struct table_config *tc; 2529f7d47b0SAlexander V. Chernikov struct table_algo *ta; 253b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 254b074b7bbSAlexander V. Chernikov uint16_t kidx; 2559f7d47b0SAlexander V. Chernikov int error; 2569f7d47b0SAlexander V. Chernikov char ta_buf[128]; 2573b3a8eb9SGleb Smirnoff 2589f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 259b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 260b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 2619f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2623b3a8eb9SGleb Smirnoff return (ESRCH); 2633b3a8eb9SGleb Smirnoff } 2643b3a8eb9SGleb Smirnoff 265b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 2669f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2673b3a8eb9SGleb Smirnoff return (EINVAL); 2683b3a8eb9SGleb Smirnoff } 2699f7d47b0SAlexander V. Chernikov 2709f7d47b0SAlexander V. Chernikov ta = tc->ta; 2719f7d47b0SAlexander V. Chernikov 2729f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 2739f7d47b0SAlexander V. Chernikov if ((error = ta->prepare_del(tei, &ta_buf)) != 0) { 2749f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2759f7d47b0SAlexander V. Chernikov return (error); 2769f7d47b0SAlexander V. Chernikov } 2779f7d47b0SAlexander V. Chernikov 278b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 279b074b7bbSAlexander V. Chernikov 280b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 2819f7d47b0SAlexander V. Chernikov error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); 2823b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2833b3a8eb9SGleb Smirnoff 2849f7d47b0SAlexander V. Chernikov if (error == 0) 2859f7d47b0SAlexander V. Chernikov tc->count--; 286b074b7bbSAlexander V. Chernikov 2879f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2883b3a8eb9SGleb Smirnoff 2899f7d47b0SAlexander V. Chernikov if (error != 0) 2909f7d47b0SAlexander V. Chernikov return (error); 2913b3a8eb9SGleb Smirnoff 2929f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 2933b3a8eb9SGleb Smirnoff return (0); 2943b3a8eb9SGleb Smirnoff } 2953b3a8eb9SGleb Smirnoff 296b074b7bbSAlexander V. Chernikov /* 2979f7d47b0SAlexander V. Chernikov * Flushes all entries in given table. 298b074b7bbSAlexander V. Chernikov */ 2993b3a8eb9SGleb Smirnoff int 300b074b7bbSAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti) 3013b3a8eb9SGleb Smirnoff { 302b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 303b074b7bbSAlexander V. Chernikov struct table_config *tc; 3049f7d47b0SAlexander V. Chernikov struct table_algo *ta; 3059f7d47b0SAlexander V. Chernikov struct table_info ti_old, ti_new, *tablestate; 3069f7d47b0SAlexander V. Chernikov void *astate_old, *astate_new; 307b074b7bbSAlexander V. Chernikov int error; 308b074b7bbSAlexander V. Chernikov uint16_t kidx; 3093b3a8eb9SGleb Smirnoff 3103b3a8eb9SGleb Smirnoff /* 3119f7d47b0SAlexander V. Chernikov * Stage 1: save table algoritm. 312b074b7bbSAlexander V. Chernikov * Reference found table to ensure it won't disappear. 3133b3a8eb9SGleb Smirnoff */ 314b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 315b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 316b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 317b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 318b074b7bbSAlexander V. Chernikov return (ESRCH); 319b074b7bbSAlexander V. Chernikov } 3209f7d47b0SAlexander V. Chernikov ta = tc->ta; 321b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 322b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3233b3a8eb9SGleb Smirnoff 324b074b7bbSAlexander V. Chernikov /* 3259f7d47b0SAlexander V. Chernikov * Stage 2: allocate new table instance using same algo. 326b074b7bbSAlexander V. Chernikov */ 3279f7d47b0SAlexander V. Chernikov memset(&ti_new, 0, sizeof(struct table_info)); 3289f7d47b0SAlexander V. Chernikov if ((error = ta->init(&astate_new, &ti_new)) != 0) { 329b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 330b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 331b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 332b074b7bbSAlexander V. Chernikov return (error); 333b074b7bbSAlexander V. Chernikov } 334b074b7bbSAlexander V. Chernikov 335b074b7bbSAlexander V. Chernikov /* 336b074b7bbSAlexander V. Chernikov * Stage 3: swap old state pointers with newly-allocated ones. 337b074b7bbSAlexander V. Chernikov * Decrease refcount. 338b074b7bbSAlexander V. Chernikov */ 339b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 340b074b7bbSAlexander V. Chernikov 341b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 342b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 3439f7d47b0SAlexander V. Chernikov tablestate = (struct table_info *)ch->tablestate; 344b074b7bbSAlexander V. Chernikov 3459f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 3469f7d47b0SAlexander V. Chernikov ti_old = tablestate[kidx]; 3479f7d47b0SAlexander V. Chernikov tablestate[kidx] = ti_new; 3489f7d47b0SAlexander V. Chernikov IPFW_WUNLOCK(ch); 349b074b7bbSAlexander V. Chernikov 3509f7d47b0SAlexander V. Chernikov astate_old = tc->astate; 3519f7d47b0SAlexander V. Chernikov tc->astate = astate_new; 3529f7d47b0SAlexander V. Chernikov tc->ti = ti_new; 3539f7d47b0SAlexander V. Chernikov tc->count = 0; 354b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 355b074b7bbSAlexander V. Chernikov 356b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3573b3a8eb9SGleb Smirnoff 358b074b7bbSAlexander V. Chernikov /* 359b074b7bbSAlexander V. Chernikov * Stage 4: perform real flush. 360b074b7bbSAlexander V. Chernikov */ 3619f7d47b0SAlexander V. Chernikov ta->destroy(astate_old, &ti_old); 3623b3a8eb9SGleb Smirnoff 3633b3a8eb9SGleb Smirnoff return (0); 3643b3a8eb9SGleb Smirnoff } 3653b3a8eb9SGleb Smirnoff 366b074b7bbSAlexander V. Chernikov /* 3679f7d47b0SAlexander V. Chernikov * Destroys table specified by @ti. 368b074b7bbSAlexander V. Chernikov */ 369b074b7bbSAlexander V. Chernikov int 3709f7d47b0SAlexander V. Chernikov ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) 371b074b7bbSAlexander V. Chernikov { 372b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 373b074b7bbSAlexander V. Chernikov struct table_config *tc; 374b074b7bbSAlexander V. Chernikov 375b074b7bbSAlexander V. Chernikov ti->set = TABLE_SET(ti->set); 376b074b7bbSAlexander V. Chernikov 377b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 378b074b7bbSAlexander V. Chernikov 379b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 380b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 381b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 382b074b7bbSAlexander V. Chernikov return (ESRCH); 383b074b7bbSAlexander V. Chernikov } 384b074b7bbSAlexander V. Chernikov 3859f7d47b0SAlexander V. Chernikov /* Do not permit destroying referenced tables */ 3869f7d47b0SAlexander V. Chernikov if (tc->no.refcnt > 0) { 387b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 388b074b7bbSAlexander V. Chernikov return (EBUSY); 389b074b7bbSAlexander V. Chernikov } 390b074b7bbSAlexander V. Chernikov 391b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 392b074b7bbSAlexander V. Chernikov unlink_table(ch, tc); 393b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 394b074b7bbSAlexander V. Chernikov 395b074b7bbSAlexander V. Chernikov /* Free obj index */ 396b074b7bbSAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, tc->no.set, tc->no.kidx) != 0) 397b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 398b074b7bbSAlexander V. Chernikov tc->no.kidx, tc->tablename); 399b074b7bbSAlexander V. Chernikov 400b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 401b074b7bbSAlexander V. Chernikov 402b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 403b074b7bbSAlexander V. Chernikov 404b074b7bbSAlexander V. Chernikov return (0); 405b074b7bbSAlexander V. Chernikov } 406b074b7bbSAlexander V. Chernikov 407b074b7bbSAlexander V. Chernikov static void 408b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, 409b074b7bbSAlexander V. Chernikov void *arg) 410b074b7bbSAlexander V. Chernikov { 411b074b7bbSAlexander V. Chernikov 412b074b7bbSAlexander V. Chernikov unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); 413b074b7bbSAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, no->set, no->kidx) != 0) 414b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 415b074b7bbSAlexander V. Chernikov no->kidx, no->name); 416b074b7bbSAlexander V. Chernikov free_table_config(ni, (struct table_config *)no); 417b074b7bbSAlexander V. Chernikov } 418b074b7bbSAlexander V. Chernikov 4193b3a8eb9SGleb Smirnoff void 4203b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch) 4213b3a8eb9SGleb Smirnoff { 4223b3a8eb9SGleb Smirnoff 423b074b7bbSAlexander V. Chernikov /* Remove all tables from working set */ 424b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 425b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 426b074b7bbSAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); 427b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 428b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 4293b3a8eb9SGleb Smirnoff 4303b3a8eb9SGleb Smirnoff /* Free pointers itself */ 4319f7d47b0SAlexander V. Chernikov free(ch->tablestate, M_IPFW); 4329f7d47b0SAlexander V. Chernikov 4339f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(ch); 434b074b7bbSAlexander V. Chernikov 435b074b7bbSAlexander V. Chernikov ipfw_objhash_destroy(CHAIN_TO_NI(ch)); 436b074b7bbSAlexander V. Chernikov free(CHAIN_TO_TCFG(ch), M_IPFW); 4373b3a8eb9SGleb Smirnoff } 4383b3a8eb9SGleb Smirnoff 4393b3a8eb9SGleb Smirnoff int 4403b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch) 4413b3a8eb9SGleb Smirnoff { 442b074b7bbSAlexander V. Chernikov struct tables_config *tcfg; 443b074b7bbSAlexander V. Chernikov 4443b3a8eb9SGleb Smirnoff /* Allocate pointers */ 4459f7d47b0SAlexander V. Chernikov ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), 4469f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 447b074b7bbSAlexander V. Chernikov 448b074b7bbSAlexander V. Chernikov tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); 449b074b7bbSAlexander V. Chernikov tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); 450b074b7bbSAlexander V. Chernikov ch->tblcfg = tcfg; 451b074b7bbSAlexander V. Chernikov 4529f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(ch); 4539f7d47b0SAlexander V. Chernikov 4543b3a8eb9SGleb Smirnoff return (0); 4553b3a8eb9SGleb Smirnoff } 4563b3a8eb9SGleb Smirnoff 4573b3a8eb9SGleb Smirnoff int 4583b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) 4593b3a8eb9SGleb Smirnoff { 4603b3a8eb9SGleb Smirnoff unsigned int ntables_old, tbl; 461b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 4629f7d47b0SAlexander V. Chernikov void *new_idx, *old_tablestate, *tablestate; 463b074b7bbSAlexander V. Chernikov int new_blocks; 4643b3a8eb9SGleb Smirnoff 4653b3a8eb9SGleb Smirnoff /* Check new value for validity */ 4663b3a8eb9SGleb Smirnoff if (ntables > IPFW_TABLES_MAX) 4673b3a8eb9SGleb Smirnoff ntables = IPFW_TABLES_MAX; 4683b3a8eb9SGleb Smirnoff 4693b3a8eb9SGleb Smirnoff /* Allocate new pointers */ 4709f7d47b0SAlexander V. Chernikov tablestate = malloc(ntables * sizeof(struct table_info), 4719f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 4729f7d47b0SAlexander V. Chernikov 473b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); 4743b3a8eb9SGleb Smirnoff 4759f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 4763b3a8eb9SGleb Smirnoff 4773b3a8eb9SGleb Smirnoff tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables; 478b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 479b074b7bbSAlexander V. Chernikov 4809f7d47b0SAlexander V. Chernikov /* Temporary restrict decreasing max_tables */ 4819f7d47b0SAlexander V. Chernikov if (ntables < V_fw_tables_max) { 4829f7d47b0SAlexander V. Chernikov 4839f7d47b0SAlexander V. Chernikov /* 4849f7d47b0SAlexander V. Chernikov * FIXME: Check if we really can shrink 4859f7d47b0SAlexander V. Chernikov */ 4869f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 487b074b7bbSAlexander V. Chernikov return (EINVAL); 488b074b7bbSAlexander V. Chernikov } 4893b3a8eb9SGleb Smirnoff 4909f7d47b0SAlexander V. Chernikov /* Copy table info/indices */ 4919f7d47b0SAlexander V. Chernikov memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl); 4929f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks); 4933b3a8eb9SGleb Smirnoff 4949f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 4959f7d47b0SAlexander V. Chernikov 4969f7d47b0SAlexander V. Chernikov /* Change pointers */ 4979f7d47b0SAlexander V. Chernikov old_tablestate = ch->tablestate; 4989f7d47b0SAlexander V. Chernikov ch->tablestate = tablestate; 4999f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks); 5003b3a8eb9SGleb Smirnoff 5013b3a8eb9SGleb Smirnoff ntables_old = V_fw_tables_max; 5023b3a8eb9SGleb Smirnoff V_fw_tables_max = ntables; 5033b3a8eb9SGleb Smirnoff 5043b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 5059f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 5063b3a8eb9SGleb Smirnoff 5073b3a8eb9SGleb Smirnoff /* Free old pointers */ 5089f7d47b0SAlexander V. Chernikov free(old_tablestate, M_IPFW); 509b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 5103b3a8eb9SGleb Smirnoff 5113b3a8eb9SGleb Smirnoff return (0); 5123b3a8eb9SGleb Smirnoff } 5133b3a8eb9SGleb Smirnoff 5143b3a8eb9SGleb Smirnoff int 5153b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 5163b3a8eb9SGleb Smirnoff uint32_t *val) 5173b3a8eb9SGleb Smirnoff { 5189f7d47b0SAlexander V. Chernikov struct table_info *ti; 5193b3a8eb9SGleb Smirnoff 5209f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 5219f7d47b0SAlexander V. Chernikov 5229f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, &addr, sizeof(in_addr_t), val)); 5233b3a8eb9SGleb Smirnoff } 5249f7d47b0SAlexander V. Chernikov 5259f7d47b0SAlexander V. Chernikov int 5269f7d47b0SAlexander V. Chernikov ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, 5279f7d47b0SAlexander V. Chernikov void *paddr, uint32_t *val) 5289f7d47b0SAlexander V. Chernikov { 5299f7d47b0SAlexander V. Chernikov struct table_info *ti; 5309f7d47b0SAlexander V. Chernikov 5319f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 5329f7d47b0SAlexander V. Chernikov 5339f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, paddr, plen, val)); 5349f7d47b0SAlexander V. Chernikov } 5359f7d47b0SAlexander V. Chernikov 5369f7d47b0SAlexander V. Chernikov /* 5379f7d47b0SAlexander V. Chernikov * Info/List/dump support for tables. 5389f7d47b0SAlexander V. Chernikov * 5399f7d47b0SAlexander V. Chernikov */ 5409f7d47b0SAlexander V. Chernikov 5419f7d47b0SAlexander V. Chernikov static void 5429f7d47b0SAlexander V. Chernikov export_table_info(struct table_config *tc, ipfw_xtable_info *i) 5439f7d47b0SAlexander V. Chernikov { 5449f7d47b0SAlexander V. Chernikov 5459f7d47b0SAlexander V. Chernikov i->type = tc->no.type; 5469f7d47b0SAlexander V. Chernikov i->ftype = tc->ftype; 5479f7d47b0SAlexander V. Chernikov i->atype = tc->ta->idx; 5489f7d47b0SAlexander V. Chernikov i->set = tc->no.set; 5499f7d47b0SAlexander V. Chernikov i->kidx = tc->no.kidx; 5509f7d47b0SAlexander V. Chernikov i->refcnt = tc->no.refcnt; 5519f7d47b0SAlexander V. Chernikov i->count = tc->count; 5529f7d47b0SAlexander V. Chernikov i->size = tc->count * sizeof(ipfw_table_xentry); 5539f7d47b0SAlexander V. Chernikov if (tc->count > 0) 5549f7d47b0SAlexander V. Chernikov i->size += sizeof(ipfw_xtable); 5559f7d47b0SAlexander V. Chernikov strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); 5569f7d47b0SAlexander V. Chernikov } 5579f7d47b0SAlexander V. Chernikov 5589f7d47b0SAlexander V. Chernikov int 5599f7d47b0SAlexander V. Chernikov ipfw_count_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh) 5609f7d47b0SAlexander V. Chernikov { 5619f7d47b0SAlexander V. Chernikov uint32_t count; 5629f7d47b0SAlexander V. Chernikov 5639f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 5649f7d47b0SAlexander V. Chernikov 5659f7d47b0SAlexander V. Chernikov olh->count = count; 5669f7d47b0SAlexander V. Chernikov olh->size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 5679f7d47b0SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 5689f7d47b0SAlexander V. Chernikov 5693b3a8eb9SGleb Smirnoff return (0); 5703b3a8eb9SGleb Smirnoff } 5713b3a8eb9SGleb Smirnoff 5723b3a8eb9SGleb Smirnoff int 5739f7d47b0SAlexander V. Chernikov ipfw_describe_table(struct ip_fw_chain *ch, struct tid_info *ti, 5749f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i) 5753b3a8eb9SGleb Smirnoff { 5769f7d47b0SAlexander V. Chernikov struct table_config *tc; 5773b3a8eb9SGleb Smirnoff 5789f7d47b0SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 5799f7d47b0SAlexander V. Chernikov return (ESRCH); 5803b3a8eb9SGleb Smirnoff 5819f7d47b0SAlexander V. Chernikov export_table_info(tc, i); 5823b3a8eb9SGleb Smirnoff 5833b3a8eb9SGleb Smirnoff return (0); 5843b3a8eb9SGleb Smirnoff } 5853b3a8eb9SGleb Smirnoff 5869f7d47b0SAlexander V. Chernikov static void 5879f7d47b0SAlexander V. Chernikov export_table_internal(struct namedobj_instance *ni, struct named_object *no, 5889f7d47b0SAlexander V. Chernikov void *arg) 5893b3a8eb9SGleb Smirnoff { 5909f7d47b0SAlexander V. Chernikov ipfw_obj_lheader *olh; 5919f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i; 5923b3a8eb9SGleb Smirnoff 5939f7d47b0SAlexander V. Chernikov olh = (ipfw_obj_lheader *)arg; 5949f7d47b0SAlexander V. Chernikov i = (ipfw_xtable_info *)(caddr_t)(olh + 1) + olh->count; 5959f7d47b0SAlexander V. Chernikov olh->count++; 5969f7d47b0SAlexander V. Chernikov 5979f7d47b0SAlexander V. Chernikov export_table_info((struct table_config *)no, i); 5989f7d47b0SAlexander V. Chernikov } 5999f7d47b0SAlexander V. Chernikov 6009f7d47b0SAlexander V. Chernikov int 6019f7d47b0SAlexander V. Chernikov ipfw_list_tables(struct ip_fw_chain *ch, struct tid_info *ti, 6029f7d47b0SAlexander V. Chernikov ipfw_obj_lheader *olh) 6039f7d47b0SAlexander V. Chernikov { 6049f7d47b0SAlexander V. Chernikov uint32_t size; 6059f7d47b0SAlexander V. Chernikov uint32_t count; 6069f7d47b0SAlexander V. Chernikov 6079f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 6089f7d47b0SAlexander V. Chernikov size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 6099f7d47b0SAlexander V. Chernikov if (size > olh->size) 6109f7d47b0SAlexander V. Chernikov return (ENOMEM); 6119f7d47b0SAlexander V. Chernikov 6129f7d47b0SAlexander V. Chernikov olh->count = 0; 6139f7d47b0SAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, olh); 6149f7d47b0SAlexander V. Chernikov 6159f7d47b0SAlexander V. Chernikov olh->count = count; 6169f7d47b0SAlexander V. Chernikov olh->size = size; 6179f7d47b0SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 6189f7d47b0SAlexander V. Chernikov 6193b3a8eb9SGleb Smirnoff return (0); 6203b3a8eb9SGleb Smirnoff } 6213b3a8eb9SGleb Smirnoff 6223b3a8eb9SGleb Smirnoff int 623b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 6243b3a8eb9SGleb Smirnoff { 625b074b7bbSAlexander V. Chernikov struct table_config *tc; 6263b3a8eb9SGleb Smirnoff 627b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 628b074b7bbSAlexander V. Chernikov return (ESRCH); 6299f7d47b0SAlexander V. Chernikov *cnt = tc->count; 6303b3a8eb9SGleb Smirnoff return (0); 6313b3a8eb9SGleb Smirnoff } 6323b3a8eb9SGleb Smirnoff 6339f7d47b0SAlexander V. Chernikov 6349f7d47b0SAlexander V. Chernikov int 6359f7d47b0SAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 6363b3a8eb9SGleb Smirnoff { 6379f7d47b0SAlexander V. Chernikov struct table_config *tc; 6389f7d47b0SAlexander V. Chernikov 6399f7d47b0SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 6409f7d47b0SAlexander V. Chernikov return (0); /* 'table all list' requires success */ 6419f7d47b0SAlexander V. Chernikov *cnt = tc->count * sizeof(ipfw_table_xentry); 6429f7d47b0SAlexander V. Chernikov if (tc->count > 0) 6439f7d47b0SAlexander V. Chernikov *cnt += sizeof(ipfw_xtable); 6449f7d47b0SAlexander V. Chernikov return (0); 6459f7d47b0SAlexander V. Chernikov } 6469f7d47b0SAlexander V. Chernikov 6479f7d47b0SAlexander V. Chernikov struct dump_args { 6489f7d47b0SAlexander V. Chernikov struct table_info *ti; 6499f7d47b0SAlexander V. Chernikov struct table_config *tc; 6509f7d47b0SAlexander V. Chernikov ipfw_table *tbl; 6519f7d47b0SAlexander V. Chernikov ipfw_xtable *xtbl; 6529f7d47b0SAlexander V. Chernikov }; 6539f7d47b0SAlexander V. Chernikov 6549f7d47b0SAlexander V. Chernikov static int 6559f7d47b0SAlexander V. Chernikov dump_table_entry(void *e, void *arg) 6569f7d47b0SAlexander V. Chernikov { 6579f7d47b0SAlexander V. Chernikov ipfw_table *tbl; 6589f7d47b0SAlexander V. Chernikov struct dump_args *da; 6599f7d47b0SAlexander V. Chernikov struct table_config *tc; 6609f7d47b0SAlexander V. Chernikov struct table_algo *ta; 6613b3a8eb9SGleb Smirnoff ipfw_table_entry *ent; 6623b3a8eb9SGleb Smirnoff 6639f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 6649f7d47b0SAlexander V. Chernikov 6659f7d47b0SAlexander V. Chernikov tbl = da->tbl; 6669f7d47b0SAlexander V. Chernikov tc = da->tc; 6679f7d47b0SAlexander V. Chernikov ta = tc->ta; 6689f7d47b0SAlexander V. Chernikov 6699f7d47b0SAlexander V. Chernikov /* Out of memory, returning */ 6703b3a8eb9SGleb Smirnoff if (tbl->cnt == tbl->size) 6713b3a8eb9SGleb Smirnoff return (1); 6723b3a8eb9SGleb Smirnoff ent = &tbl->ent[tbl->cnt]; 6733b3a8eb9SGleb Smirnoff ent->tbl = tbl->tbl; 6743b3a8eb9SGleb Smirnoff tbl->cnt++; 6759f7d47b0SAlexander V. Chernikov 6769f7d47b0SAlexander V. Chernikov return (ta->dump_entry(tc->astate, da->ti, e, ent)); 6773b3a8eb9SGleb Smirnoff } 6783b3a8eb9SGleb Smirnoff 6793b3a8eb9SGleb Smirnoff int 680b074b7bbSAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_table *tbl) 6813b3a8eb9SGleb Smirnoff { 682b074b7bbSAlexander V. Chernikov struct table_config *tc; 6839f7d47b0SAlexander V. Chernikov struct table_algo *ta; 6849f7d47b0SAlexander V. Chernikov struct dump_args da; 6853b3a8eb9SGleb Smirnoff 6863b3a8eb9SGleb Smirnoff tbl->cnt = 0; 6873b3a8eb9SGleb Smirnoff 688b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 689b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 6909f7d47b0SAlexander V. Chernikov 6919f7d47b0SAlexander V. Chernikov ta = tc->ta; 6929f7d47b0SAlexander V. Chernikov 6939f7d47b0SAlexander V. Chernikov if (ta->dump_entry == NULL) 6949f7d47b0SAlexander V. Chernikov return (0); /* Legacy dump support is not necessary */ 6959f7d47b0SAlexander V. Chernikov 6969f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 6979f7d47b0SAlexander V. Chernikov da.tc = tc; 6989f7d47b0SAlexander V. Chernikov da.tbl = tbl; 6999f7d47b0SAlexander V. Chernikov 7009f7d47b0SAlexander V. Chernikov tbl->cnt = 0; 7019f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_entry, &da); 7029f7d47b0SAlexander V. Chernikov 7033b3a8eb9SGleb Smirnoff return (0); 7043b3a8eb9SGleb Smirnoff } 7053b3a8eb9SGleb Smirnoff 7063b3a8eb9SGleb Smirnoff 7073b3a8eb9SGleb Smirnoff static int 7089f7d47b0SAlexander V. Chernikov dump_table_xentry(void *e, void *arg) 7093b3a8eb9SGleb Smirnoff { 7109f7d47b0SAlexander V. Chernikov ipfw_xtable *xtbl; 7119f7d47b0SAlexander V. Chernikov struct dump_args *da; 7129f7d47b0SAlexander V. Chernikov struct table_config *tc; 7139f7d47b0SAlexander V. Chernikov struct table_algo *ta; 7143b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 7153b3a8eb9SGleb Smirnoff 7169f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 7179f7d47b0SAlexander V. Chernikov 7189f7d47b0SAlexander V. Chernikov xtbl = da->xtbl; 7199f7d47b0SAlexander V. Chernikov tc = da->tc; 7209f7d47b0SAlexander V. Chernikov ta = tc->ta; 7219f7d47b0SAlexander V. Chernikov 7223b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 7239f7d47b0SAlexander V. Chernikov if (xtbl->cnt == xtbl->size) 7243b3a8eb9SGleb Smirnoff return (1); 7259f7d47b0SAlexander V. Chernikov xent = &xtbl->xent[xtbl->cnt]; 7263b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 7279f7d47b0SAlexander V. Chernikov xent->tbl = xtbl->tbl; 7289f7d47b0SAlexander V. Chernikov xtbl->cnt++; 7299f7d47b0SAlexander V. Chernikov 7309f7d47b0SAlexander V. Chernikov return (ta->dump_xentry(tc->astate, da->ti, e, xent)); 7319f7d47b0SAlexander V. Chernikov } 7329f7d47b0SAlexander V. Chernikov 7339f7d47b0SAlexander V. Chernikov 7349f7d47b0SAlexander V. Chernikov int 7359f7d47b0SAlexander V. Chernikov ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_xtable *xtbl) 7369f7d47b0SAlexander V. Chernikov { 7379f7d47b0SAlexander V. Chernikov struct table_config *tc; 7389f7d47b0SAlexander V. Chernikov struct table_algo *ta; 7399f7d47b0SAlexander V. Chernikov struct dump_args da; 7409f7d47b0SAlexander V. Chernikov 7419f7d47b0SAlexander V. Chernikov xtbl->cnt = 0; 7429f7d47b0SAlexander V. Chernikov 7439f7d47b0SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 7449f7d47b0SAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 7459f7d47b0SAlexander V. Chernikov 7469f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 7479f7d47b0SAlexander V. Chernikov da.tc = tc; 7489f7d47b0SAlexander V. Chernikov da.xtbl = xtbl; 7499f7d47b0SAlexander V. Chernikov xtbl->type = tc->no.type; 7509f7d47b0SAlexander V. Chernikov ta = tc->ta; 7519f7d47b0SAlexander V. Chernikov 7529f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 7539f7d47b0SAlexander V. Chernikov 7543b3a8eb9SGleb Smirnoff return (0); 7553b3a8eb9SGleb Smirnoff } 7563b3a8eb9SGleb Smirnoff 7579f7d47b0SAlexander V. Chernikov /* 7589f7d47b0SAlexander V. Chernikov * Table algorithms 7599f7d47b0SAlexander V. Chernikov */ 7603b3a8eb9SGleb Smirnoff 7619f7d47b0SAlexander V. Chernikov /* 7629f7d47b0SAlexander V. Chernikov * Finds algoritm by index or table type 7639f7d47b0SAlexander V. Chernikov */ 7649f7d47b0SAlexander V. Chernikov static struct table_algo * 7659f7d47b0SAlexander V. Chernikov find_table_algo(struct tables_config *tcfg, struct tid_info *ti) 7669f7d47b0SAlexander V. Chernikov { 7679f7d47b0SAlexander V. Chernikov 7689f7d47b0SAlexander V. Chernikov /* Search by index */ 7699f7d47b0SAlexander V. Chernikov if (ti->atype != 0) { 7709f7d47b0SAlexander V. Chernikov if (ti->atype > tcfg->algo_count) 7719f7d47b0SAlexander V. Chernikov return (NULL); 7729f7d47b0SAlexander V. Chernikov return (tcfg->algo[ti->atype]); 7739f7d47b0SAlexander V. Chernikov } 7749f7d47b0SAlexander V. Chernikov 7759f7d47b0SAlexander V. Chernikov /* Search by type */ 7769f7d47b0SAlexander V. Chernikov switch (ti->type) { 7773b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 7789f7d47b0SAlexander V. Chernikov return (&radix_cidr); 7793b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 7809f7d47b0SAlexander V. Chernikov return (&radix_iface); 7813b3a8eb9SGleb Smirnoff } 7823b3a8eb9SGleb Smirnoff 7839f7d47b0SAlexander V. Chernikov return (NULL); 7843b3a8eb9SGleb Smirnoff } 7853b3a8eb9SGleb Smirnoff 7869f7d47b0SAlexander V. Chernikov void 7879f7d47b0SAlexander V. Chernikov ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta) 7883b3a8eb9SGleb Smirnoff { 7899f7d47b0SAlexander V. Chernikov struct tables_config *tcfg; 7903b3a8eb9SGleb Smirnoff 7919f7d47b0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 792b074b7bbSAlexander V. Chernikov 7939f7d47b0SAlexander V. Chernikov KASSERT(tcfg->algo_count < 255, ("Increase algo array size")); 7949f7d47b0SAlexander V. Chernikov 7959f7d47b0SAlexander V. Chernikov tcfg->algo[++tcfg->algo_count] = ta; 7969f7d47b0SAlexander V. Chernikov ta->idx = tcfg->algo_count; 7973b3a8eb9SGleb Smirnoff } 7983b3a8eb9SGleb Smirnoff 7999f7d47b0SAlexander V. Chernikov 800b074b7bbSAlexander V. Chernikov /* 801b074b7bbSAlexander V. Chernikov * Tables rewriting code 802b074b7bbSAlexander V. Chernikov * 803b074b7bbSAlexander V. Chernikov */ 804b074b7bbSAlexander V. Chernikov 805b074b7bbSAlexander V. Chernikov /* 806b074b7bbSAlexander V. Chernikov * Determine table number and lookup type for @cmd. 807b074b7bbSAlexander V. Chernikov * Fill @tbl and @type with appropriate values. 808b074b7bbSAlexander V. Chernikov * Returns 0 for relevant opcodes, 1 otherwise. 809b074b7bbSAlexander V. Chernikov */ 810b074b7bbSAlexander V. Chernikov static int 811b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 812b074b7bbSAlexander V. Chernikov { 813b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 814b074b7bbSAlexander V. Chernikov int skip; 815b074b7bbSAlexander V. Chernikov uint16_t v; 816b074b7bbSAlexander V. Chernikov 817b074b7bbSAlexander V. Chernikov skip = 1; 818b074b7bbSAlexander V. Chernikov 819b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 820b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 821b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 822b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 823b074b7bbSAlexander V. Chernikov *puidx = cmd->arg1; 824b074b7bbSAlexander V. Chernikov /* Assume CIDR by default */ 825b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 826b074b7bbSAlexander V. Chernikov skip = 0; 827b074b7bbSAlexander V. Chernikov 828b074b7bbSAlexander V. Chernikov if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { 829b074b7bbSAlexander V. Chernikov /* 830b074b7bbSAlexander V. Chernikov * generic lookup. The key must be 831b074b7bbSAlexander V. Chernikov * in 32bit big-endian format. 832b074b7bbSAlexander V. Chernikov */ 833b074b7bbSAlexander V. Chernikov v = ((ipfw_insn_u32 *)cmd)->d[1]; 834b074b7bbSAlexander V. Chernikov switch (v) { 835b074b7bbSAlexander V. Chernikov case 0: 836b074b7bbSAlexander V. Chernikov case 1: 837b074b7bbSAlexander V. Chernikov /* IPv4 src/dst */ 838b074b7bbSAlexander V. Chernikov break; 839b074b7bbSAlexander V. Chernikov case 2: 840b074b7bbSAlexander V. Chernikov case 3: 841b074b7bbSAlexander V. Chernikov /* src/dst port */ 842b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 843b074b7bbSAlexander V. Chernikov break; 844b074b7bbSAlexander V. Chernikov case 4: 845b074b7bbSAlexander V. Chernikov /* uid/gid */ 846b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 847b074b7bbSAlexander V. Chernikov case 5: 848b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 849b074b7bbSAlexander V. Chernikov /* jid */ 850b074b7bbSAlexander V. Chernikov case 6: 851b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 852b074b7bbSAlexander V. Chernikov /* dscp */ 853b074b7bbSAlexander V. Chernikov break; 854b074b7bbSAlexander V. Chernikov } 855b074b7bbSAlexander V. Chernikov } 856b074b7bbSAlexander V. Chernikov break; 857b074b7bbSAlexander V. Chernikov case O_XMIT: 858b074b7bbSAlexander V. Chernikov case O_RECV: 859b074b7bbSAlexander V. Chernikov case O_VIA: 860b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 861b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 862b074b7bbSAlexander V. Chernikov if (cmdif->name[0] != '\1') 863b074b7bbSAlexander V. Chernikov break; 864b074b7bbSAlexander V. Chernikov 865b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 866b074b7bbSAlexander V. Chernikov *puidx = cmdif->p.glob; 867b074b7bbSAlexander V. Chernikov skip = 0; 868b074b7bbSAlexander V. Chernikov break; 869b074b7bbSAlexander V. Chernikov } 870b074b7bbSAlexander V. Chernikov 871b074b7bbSAlexander V. Chernikov return (skip); 872b074b7bbSAlexander V. Chernikov } 873b074b7bbSAlexander V. Chernikov 874b074b7bbSAlexander V. Chernikov /* 875b074b7bbSAlexander V. Chernikov * Sets new table value for given opcode. 876b074b7bbSAlexander V. Chernikov * Assume the same opcodes as classify_table_opcode() 877b074b7bbSAlexander V. Chernikov */ 878b074b7bbSAlexander V. Chernikov static void 879b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx) 880b074b7bbSAlexander V. Chernikov { 881b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 882b074b7bbSAlexander V. Chernikov 883b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 884b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 885b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 886b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 887b074b7bbSAlexander V. Chernikov cmd->arg1 = idx; 888b074b7bbSAlexander V. Chernikov break; 889b074b7bbSAlexander V. Chernikov case O_XMIT: 890b074b7bbSAlexander V. Chernikov case O_RECV: 891b074b7bbSAlexander V. Chernikov case O_VIA: 892b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 893b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 894b074b7bbSAlexander V. Chernikov cmdif->p.glob = idx; 895b074b7bbSAlexander V. Chernikov break; 896b074b7bbSAlexander V. Chernikov } 897b074b7bbSAlexander V. Chernikov } 898b074b7bbSAlexander V. Chernikov 899b074b7bbSAlexander V. Chernikov static char * 900b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx) 901b074b7bbSAlexander V. Chernikov { 9029f7d47b0SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 903b074b7bbSAlexander V. Chernikov uintptr_t pa, pe; 904b074b7bbSAlexander V. Chernikov int l; 905b074b7bbSAlexander V. Chernikov 906b074b7bbSAlexander V. Chernikov pa = (uintptr_t)tlvs; 907b074b7bbSAlexander V. Chernikov pe = pa + len; 908b074b7bbSAlexander V. Chernikov l = 0; 909b074b7bbSAlexander V. Chernikov for (; pa < pe; pa += l) { 9109f7d47b0SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)pa; 911b074b7bbSAlexander V. Chernikov l = ntlv->head.length; 912b074b7bbSAlexander V. Chernikov if (ntlv->head.type != IPFW_TLV_NAME) 913b074b7bbSAlexander V. Chernikov continue; 914b074b7bbSAlexander V. Chernikov if (ntlv->idx != uidx) 915b074b7bbSAlexander V. Chernikov continue; 916b074b7bbSAlexander V. Chernikov 917b074b7bbSAlexander V. Chernikov return (ntlv->name); 918b074b7bbSAlexander V. Chernikov } 919b074b7bbSAlexander V. Chernikov 920b074b7bbSAlexander V. Chernikov return (NULL); 921b074b7bbSAlexander V. Chernikov } 922b074b7bbSAlexander V. Chernikov 923b074b7bbSAlexander V. Chernikov static struct table_config * 924b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti) 925b074b7bbSAlexander V. Chernikov { 926b074b7bbSAlexander V. Chernikov char *name, bname[16]; 927b074b7bbSAlexander V. Chernikov struct named_object *no; 928b074b7bbSAlexander V. Chernikov 929b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 930b074b7bbSAlexander V. Chernikov name = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 931b074b7bbSAlexander V. Chernikov if (name == NULL) 932b074b7bbSAlexander V. Chernikov return (NULL); 933b074b7bbSAlexander V. Chernikov } else { 934b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 935b074b7bbSAlexander V. Chernikov name = bname; 936b074b7bbSAlexander V. Chernikov } 937b074b7bbSAlexander V. Chernikov 938b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_name(ni, ti->set, name); 939b074b7bbSAlexander V. Chernikov 940b074b7bbSAlexander V. Chernikov return ((struct table_config *)no); 941b074b7bbSAlexander V. Chernikov } 942b074b7bbSAlexander V. Chernikov 943b074b7bbSAlexander V. Chernikov static struct table_config * 9449f7d47b0SAlexander V. Chernikov alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti, 9459f7d47b0SAlexander V. Chernikov struct table_algo *ta) 946b074b7bbSAlexander V. Chernikov { 947b074b7bbSAlexander V. Chernikov char *name, bname[16]; 948b074b7bbSAlexander V. Chernikov struct table_config *tc; 949b074b7bbSAlexander V. Chernikov int error; 950b074b7bbSAlexander V. Chernikov 951b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 952b074b7bbSAlexander V. Chernikov name = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 953b074b7bbSAlexander V. Chernikov if (name == NULL) 954b074b7bbSAlexander V. Chernikov return (NULL); 955b074b7bbSAlexander V. Chernikov } else { 956b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 957b074b7bbSAlexander V. Chernikov name = bname; 958b074b7bbSAlexander V. Chernikov } 959b074b7bbSAlexander V. Chernikov 960b074b7bbSAlexander V. Chernikov tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO); 961b074b7bbSAlexander V. Chernikov tc->no.name = tc->tablename; 962b074b7bbSAlexander V. Chernikov tc->no.type = ti->type; 963b074b7bbSAlexander V. Chernikov tc->no.set = ti->set; 9649f7d47b0SAlexander V. Chernikov tc->ta = ta; 965b074b7bbSAlexander V. Chernikov strlcpy(tc->tablename, name, sizeof(tc->tablename)); 966b074b7bbSAlexander V. Chernikov 967b074b7bbSAlexander V. Chernikov if (ti->tlvs == NULL) { 968b074b7bbSAlexander V. Chernikov tc->no.compat = 1; 969b074b7bbSAlexander V. Chernikov tc->no.uidx = ti->uidx; 970b074b7bbSAlexander V. Chernikov } 971b074b7bbSAlexander V. Chernikov 972b074b7bbSAlexander V. Chernikov /* Preallocate data structures for new tables */ 9739f7d47b0SAlexander V. Chernikov error = ta->init(&tc->astate, &tc->ti); 974b074b7bbSAlexander V. Chernikov if (error != 0) { 975b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 976b074b7bbSAlexander V. Chernikov return (NULL); 977b074b7bbSAlexander V. Chernikov } 978b074b7bbSAlexander V. Chernikov 979b074b7bbSAlexander V. Chernikov return (tc); 980b074b7bbSAlexander V. Chernikov } 981b074b7bbSAlexander V. Chernikov 982b074b7bbSAlexander V. Chernikov static void 983b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc) 984b074b7bbSAlexander V. Chernikov { 985b074b7bbSAlexander V. Chernikov 986b074b7bbSAlexander V. Chernikov if (tc->linked == 0) 9879f7d47b0SAlexander V. Chernikov tc->ta->destroy(&tc->astate, &tc->ti); 988b074b7bbSAlexander V. Chernikov 989b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 990b074b7bbSAlexander V. Chernikov } 991b074b7bbSAlexander V. Chernikov 992b074b7bbSAlexander V. Chernikov /* 993b074b7bbSAlexander V. Chernikov * Links @tc to @chain table named instance. 994b074b7bbSAlexander V. Chernikov * Sets appropriate type/states in @chain table info. 995b074b7bbSAlexander V. Chernikov */ 996b074b7bbSAlexander V. Chernikov static void 9979f7d47b0SAlexander V. Chernikov link_table(struct ip_fw_chain *ch, struct table_config *tc) 998b074b7bbSAlexander V. Chernikov { 999b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 10009f7d47b0SAlexander V. Chernikov struct table_info *ti; 1001b074b7bbSAlexander V. Chernikov uint16_t kidx; 1002b074b7bbSAlexander V. Chernikov 10039f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 10049f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1005b074b7bbSAlexander V. Chernikov 10069f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1007b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1008b074b7bbSAlexander V. Chernikov 1009b074b7bbSAlexander V. Chernikov ipfw_objhash_add(ni, &tc->no); 10109f7d47b0SAlexander V. Chernikov 10119f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 10129f7d47b0SAlexander V. Chernikov *ti = tc->ti; 1013b074b7bbSAlexander V. Chernikov 1014b074b7bbSAlexander V. Chernikov tc->linked = 1; 1015b074b7bbSAlexander V. Chernikov } 1016b074b7bbSAlexander V. Chernikov 1017b074b7bbSAlexander V. Chernikov /* 1018b074b7bbSAlexander V. Chernikov * Unlinks @tc from @chain table named instance. 1019b074b7bbSAlexander V. Chernikov * Zeroes states in @chain and stores them in @tc. 1020b074b7bbSAlexander V. Chernikov */ 1021b074b7bbSAlexander V. Chernikov static void 10229f7d47b0SAlexander V. Chernikov unlink_table(struct ip_fw_chain *ch, struct table_config *tc) 1023b074b7bbSAlexander V. Chernikov { 1024b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 10259f7d47b0SAlexander V. Chernikov struct table_info *ti; 1026b074b7bbSAlexander V. Chernikov uint16_t kidx; 1027b074b7bbSAlexander V. Chernikov 10289f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 10299f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1030b074b7bbSAlexander V. Chernikov 10319f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1032b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1033b074b7bbSAlexander V. Chernikov 10349f7d47b0SAlexander V. Chernikov /* Clear state. @ti copy is already saved inside @tc */ 1035b074b7bbSAlexander V. Chernikov ipfw_objhash_del(ni, &tc->no); 10369f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 10379f7d47b0SAlexander V. Chernikov memset(ti, 0, sizeof(struct table_info)); 1038b074b7bbSAlexander V. Chernikov tc->linked = 0; 1039b074b7bbSAlexander V. Chernikov } 1040b074b7bbSAlexander V. Chernikov 1041b074b7bbSAlexander V. Chernikov /* 1042b074b7bbSAlexander V. Chernikov * Finds named object by @uidx number. 1043b074b7bbSAlexander V. Chernikov * Refs found object, allocate new index for non-existing object. 1044b074b7bbSAlexander V. Chernikov * Fills in @pidx with userland/kernel indexes. 1045b074b7bbSAlexander V. Chernikov * 1046b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1047b074b7bbSAlexander V. Chernikov */ 1048b074b7bbSAlexander V. Chernikov static int 1049b074b7bbSAlexander V. Chernikov bind_table(struct namedobj_instance *ni, struct rule_check_info *ci, 1050b074b7bbSAlexander V. Chernikov struct obj_idx *pidx, struct tid_info *ti) 1051b074b7bbSAlexander V. Chernikov { 1052b074b7bbSAlexander V. Chernikov struct table_config *tc; 1053b074b7bbSAlexander V. Chernikov 1054b074b7bbSAlexander V. Chernikov pidx->uidx = ti->uidx; 1055b074b7bbSAlexander V. Chernikov pidx->type = ti->type; 1056b074b7bbSAlexander V. Chernikov 10579f7d47b0SAlexander V. Chernikov tc = find_table(ni, ti); 10589f7d47b0SAlexander V. Chernikov 1059b074b7bbSAlexander V. Chernikov if (tc == NULL) { 1060b074b7bbSAlexander V. Chernikov /* Try to acquire refcount */ 1061b074b7bbSAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, ti->set, &pidx->kidx) != 0) { 1062b074b7bbSAlexander V. Chernikov printf("Unable to allocate table index in set %u." 1063b074b7bbSAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 1064b074b7bbSAlexander V. Chernikov ti->set); 1065b074b7bbSAlexander V. Chernikov return (EBUSY); 1066b074b7bbSAlexander V. Chernikov } 1067b074b7bbSAlexander V. Chernikov 1068b074b7bbSAlexander V. Chernikov pidx->new = 1; 1069b074b7bbSAlexander V. Chernikov ci->new_tables++; 1070b074b7bbSAlexander V. Chernikov 1071b074b7bbSAlexander V. Chernikov return (0); 1072b074b7bbSAlexander V. Chernikov } 1073b074b7bbSAlexander V. Chernikov 1074b074b7bbSAlexander V. Chernikov /* Check if table type if valid first */ 1075b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) 1076b074b7bbSAlexander V. Chernikov return (EINVAL); 1077b074b7bbSAlexander V. Chernikov 1078b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 1079b074b7bbSAlexander V. Chernikov 1080b074b7bbSAlexander V. Chernikov pidx->kidx = tc->no.kidx; 1081b074b7bbSAlexander V. Chernikov 1082b074b7bbSAlexander V. Chernikov return (0); 1083b074b7bbSAlexander V. Chernikov } 1084b074b7bbSAlexander V. Chernikov 1085b074b7bbSAlexander V. Chernikov /* 1086b074b7bbSAlexander V. Chernikov * Compatibility function for old ipfw(8) binaries. 1087b074b7bbSAlexander V. Chernikov * Rewrites table kernel indices with userland ones. 1088b074b7bbSAlexander V. Chernikov * Works for \d+ talbes only (e.g. for tables, converted 1089b074b7bbSAlexander V. Chernikov * from old numbered system calls). 1090b074b7bbSAlexander V. Chernikov * 1091b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1092b074b7bbSAlexander V. Chernikov * Raises error on any other tables. 1093b074b7bbSAlexander V. Chernikov */ 1094b074b7bbSAlexander V. Chernikov int 1095b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule) 1096b074b7bbSAlexander V. Chernikov { 1097b074b7bbSAlexander V. Chernikov int cmdlen, l; 1098b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1099b074b7bbSAlexander V. Chernikov uint32_t set; 1100b074b7bbSAlexander V. Chernikov uint16_t kidx; 1101b074b7bbSAlexander V. Chernikov uint8_t type; 1102b074b7bbSAlexander V. Chernikov struct named_object *no; 1103b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1104b074b7bbSAlexander V. Chernikov 1105b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1106b074b7bbSAlexander V. Chernikov 1107b074b7bbSAlexander V. Chernikov set = TABLE_SET(rule->set); 1108b074b7bbSAlexander V. Chernikov 1109b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1110b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1111b074b7bbSAlexander V. Chernikov cmdlen = 0; 1112b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1113b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1114b074b7bbSAlexander V. Chernikov 1115b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1116b074b7bbSAlexander V. Chernikov continue; 1117b074b7bbSAlexander V. Chernikov 1118b074b7bbSAlexander V. Chernikov if ((no = ipfw_objhash_lookup_idx(ni, set, kidx)) == NULL) 1119b074b7bbSAlexander V. Chernikov return (1); 1120b074b7bbSAlexander V. Chernikov 1121b074b7bbSAlexander V. Chernikov if (no->compat == 0) 1122b074b7bbSAlexander V. Chernikov return (2); 1123b074b7bbSAlexander V. Chernikov 1124b074b7bbSAlexander V. Chernikov update_table_opcode(cmd, no->uidx); 1125b074b7bbSAlexander V. Chernikov } 1126b074b7bbSAlexander V. Chernikov 1127b074b7bbSAlexander V. Chernikov return (0); 1128b074b7bbSAlexander V. Chernikov } 1129b074b7bbSAlexander V. Chernikov 1130b074b7bbSAlexander V. Chernikov 1131b074b7bbSAlexander V. Chernikov /* 1132b074b7bbSAlexander V. Chernikov * Checks is opcode is referencing table of appropriate type. 1133b074b7bbSAlexander V. Chernikov * Adds reference count for found table if true. 1134b074b7bbSAlexander V. Chernikov * Rewrites user-supplied opcode values with kernel ones. 1135b074b7bbSAlexander V. Chernikov * 1136b074b7bbSAlexander V. Chernikov * Returns 0 on success and appropriate error code otherwise. 1137b074b7bbSAlexander V. Chernikov */ 1138b074b7bbSAlexander V. Chernikov int 1139b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, 1140b074b7bbSAlexander V. Chernikov struct rule_check_info *ci) 1141b074b7bbSAlexander V. Chernikov { 1142b074b7bbSAlexander V. Chernikov int cmdlen, error, ftype, l; 1143b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1144b074b7bbSAlexander V. Chernikov uint16_t uidx; 1145b074b7bbSAlexander V. Chernikov uint8_t type; 1146b074b7bbSAlexander V. Chernikov struct table_config *tc; 11479f7d47b0SAlexander V. Chernikov struct table_algo *ta; 1148b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1149b074b7bbSAlexander V. Chernikov struct named_object *no, *no_n, *no_tmp; 1150b074b7bbSAlexander V. Chernikov struct obj_idx *pidx, *p, *oib; 1151b074b7bbSAlexander V. Chernikov struct namedobjects_head nh; 1152b074b7bbSAlexander V. Chernikov struct tid_info ti; 1153b074b7bbSAlexander V. Chernikov 1154b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1155b074b7bbSAlexander V. Chernikov 1156b074b7bbSAlexander V. Chernikov /* 1157b074b7bbSAlexander V. Chernikov * Prepare an array for storing opcode indices. 1158b074b7bbSAlexander V. Chernikov * Use stack allocation by default. 1159b074b7bbSAlexander V. Chernikov */ 1160b074b7bbSAlexander V. Chernikov if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 1161b074b7bbSAlexander V. Chernikov /* Stack */ 1162b074b7bbSAlexander V. Chernikov pidx = ci->obuf; 1163b074b7bbSAlexander V. Chernikov } else 1164b074b7bbSAlexander V. Chernikov pidx = malloc(ci->table_opcodes * sizeof(struct obj_idx), 1165b074b7bbSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1166b074b7bbSAlexander V. Chernikov 1167b074b7bbSAlexander V. Chernikov oib = pidx; 1168b074b7bbSAlexander V. Chernikov error = 0; 1169b074b7bbSAlexander V. Chernikov 1170b074b7bbSAlexander V. Chernikov type = 0; 1171b074b7bbSAlexander V. Chernikov ftype = 0; 1172b074b7bbSAlexander V. Chernikov 1173b074b7bbSAlexander V. Chernikov ci->tableset = TABLE_SET(ci->krule->set); 1174b074b7bbSAlexander V. Chernikov 1175b074b7bbSAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 1176b074b7bbSAlexander V. Chernikov ti.set = ci->tableset; 1177b074b7bbSAlexander V. Chernikov ti.tlvs = ci->tlvs; 1178b074b7bbSAlexander V. Chernikov ti.tlen = ci->tlen; 1179b074b7bbSAlexander V. Chernikov 1180b074b7bbSAlexander V. Chernikov /* 1181b074b7bbSAlexander V. Chernikov * Stage 1: reference existing tables and determine number 1182b074b7bbSAlexander V. Chernikov * of tables we need to allocate 1183b074b7bbSAlexander V. Chernikov */ 1184b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(chain); 1185b074b7bbSAlexander V. Chernikov 1186b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 1187b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 1188b074b7bbSAlexander V. Chernikov cmdlen = 0; 1189b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1190b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1191b074b7bbSAlexander V. Chernikov 1192b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &ti.uidx, &ti.type) != 0) 1193b074b7bbSAlexander V. Chernikov continue; 1194b074b7bbSAlexander V. Chernikov 1195b074b7bbSAlexander V. Chernikov /* 1196b074b7bbSAlexander V. Chernikov * Got table opcode with necessary info. 1197b074b7bbSAlexander V. Chernikov * Try to reference existing tables and allocate 1198b074b7bbSAlexander V. Chernikov * indices for non-existing one while holding write lock. 1199b074b7bbSAlexander V. Chernikov */ 12009f7d47b0SAlexander V. Chernikov if ((error = bind_table(ni, ci, pidx, &ti)) != 0) { 12019f7d47b0SAlexander V. Chernikov printf("error!\n"); 1202b074b7bbSAlexander V. Chernikov break; 12039f7d47b0SAlexander V. Chernikov } 1204b074b7bbSAlexander V. Chernikov 1205b074b7bbSAlexander V. Chernikov /* 1206b074b7bbSAlexander V. Chernikov * @pidx stores either existing ref'd table id or new one. 1207b074b7bbSAlexander V. Chernikov * Move to next index 1208b074b7bbSAlexander V. Chernikov */ 1209b074b7bbSAlexander V. Chernikov 1210b074b7bbSAlexander V. Chernikov pidx++; 1211b074b7bbSAlexander V. Chernikov } 1212b074b7bbSAlexander V. Chernikov 1213b074b7bbSAlexander V. Chernikov if (error != 0) { 1214b074b7bbSAlexander V. Chernikov /* Unref everything we have already done */ 1215b074b7bbSAlexander V. Chernikov for (p = oib; p < pidx; p++) { 1216b074b7bbSAlexander V. Chernikov if (p->new != 0) { 1217b074b7bbSAlexander V. Chernikov ipfw_objhash_free_idx(ni, ci->tableset,p->kidx); 1218b074b7bbSAlexander V. Chernikov continue; 1219b074b7bbSAlexander V. Chernikov } 1220b074b7bbSAlexander V. Chernikov 1221b074b7bbSAlexander V. Chernikov /* Find & unref by existing idx */ 1222b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_idx(ni, ci->tableset, p->kidx); 1223b074b7bbSAlexander V. Chernikov KASSERT(no!=NULL, ("Ref'd table %d disappeared", 1224b074b7bbSAlexander V. Chernikov p->kidx)); 1225b074b7bbSAlexander V. Chernikov 1226b074b7bbSAlexander V. Chernikov no->refcnt--; 1227b074b7bbSAlexander V. Chernikov } 1228b074b7bbSAlexander V. Chernikov 1229b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1230b074b7bbSAlexander V. Chernikov 1231b074b7bbSAlexander V. Chernikov if (oib != ci->obuf) 1232b074b7bbSAlexander V. Chernikov free(oib, M_IPFW); 1233b074b7bbSAlexander V. Chernikov 1234b074b7bbSAlexander V. Chernikov return (error); 1235b074b7bbSAlexander V. Chernikov } 1236b074b7bbSAlexander V. Chernikov 1237b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1238b074b7bbSAlexander V. Chernikov 1239b074b7bbSAlexander V. Chernikov /* 1240b074b7bbSAlexander V. Chernikov * Stage 2: allocate table configs for every non-existent table 1241b074b7bbSAlexander V. Chernikov */ 1242b074b7bbSAlexander V. Chernikov 1243b074b7bbSAlexander V. Chernikov /* Prepare queue to store configs */ 1244b074b7bbSAlexander V. Chernikov TAILQ_INIT(&nh); 12459f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 1246b074b7bbSAlexander V. Chernikov for (p = oib; p < pidx; p++) { 1247b074b7bbSAlexander V. Chernikov if (p->new == 0) 1248b074b7bbSAlexander V. Chernikov continue; 1249b074b7bbSAlexander V. Chernikov 1250b074b7bbSAlexander V. Chernikov /* TODO: get name from TLV */ 1251b074b7bbSAlexander V. Chernikov ti.uidx = p->uidx; 1252b074b7bbSAlexander V. Chernikov ti.type = p->type; 12539f7d47b0SAlexander V. Chernikov ti.atype = 0; 1254b074b7bbSAlexander V. Chernikov 12559f7d47b0SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti); 12569f7d47b0SAlexander V. Chernikov if (ta == NULL) { 12579f7d47b0SAlexander V. Chernikov error = ENOTSUP; 12589f7d47b0SAlexander V. Chernikov goto free; 12599f7d47b0SAlexander V. Chernikov } 12609f7d47b0SAlexander V. Chernikov tc = alloc_table_config(ni, &ti, ta); 1261b074b7bbSAlexander V. Chernikov 1262b074b7bbSAlexander V. Chernikov if (tc == NULL) { 1263b074b7bbSAlexander V. Chernikov error = ENOMEM; 1264b074b7bbSAlexander V. Chernikov goto free; 1265b074b7bbSAlexander V. Chernikov } 1266b074b7bbSAlexander V. Chernikov 1267b074b7bbSAlexander V. Chernikov tc->no.kidx = p->kidx; 1268b074b7bbSAlexander V. Chernikov tc->no.refcnt = 1; 1269b074b7bbSAlexander V. Chernikov 1270b074b7bbSAlexander V. Chernikov /* Add to list */ 1271b074b7bbSAlexander V. Chernikov TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next); 1272b074b7bbSAlexander V. Chernikov } 1273b074b7bbSAlexander V. Chernikov 1274b074b7bbSAlexander V. Chernikov /* 1275b074b7bbSAlexander V. Chernikov * Stage 2.1: Check if we're going to create 2 tables 1276b074b7bbSAlexander V. Chernikov * with the same name, but different table types. 1277b074b7bbSAlexander V. Chernikov */ 1278b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no, &nh, nn_next) { 1279b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no_tmp, &nh, nn_next) { 1280b074b7bbSAlexander V. Chernikov if (strcmp(no->name, no_tmp->name) != 0) 1281b074b7bbSAlexander V. Chernikov continue; 1282b074b7bbSAlexander V. Chernikov if (no->type != no_tmp->type) { 1283b074b7bbSAlexander V. Chernikov error = EINVAL; 1284b074b7bbSAlexander V. Chernikov goto free; 1285b074b7bbSAlexander V. Chernikov } 1286b074b7bbSAlexander V. Chernikov } 1287b074b7bbSAlexander V. Chernikov } 12889f7d47b0SAlexander V. Chernikov } 1289b074b7bbSAlexander V. Chernikov 12909f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 12919f7d47b0SAlexander V. Chernikov 12929f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 1293b074b7bbSAlexander V. Chernikov /* 1294b074b7bbSAlexander V. Chernikov * Stage 3: link & reference new table configs 1295b074b7bbSAlexander V. Chernikov */ 1296b074b7bbSAlexander V. Chernikov 1297b074b7bbSAlexander V. Chernikov 1298b074b7bbSAlexander V. Chernikov /* 1299b074b7bbSAlexander V. Chernikov * Step 3.1: Check if some tables we need to create have been 1300b074b7bbSAlexander V. Chernikov * already created with different table type. 1301b074b7bbSAlexander V. Chernikov */ 1302b074b7bbSAlexander V. Chernikov 1303b074b7bbSAlexander V. Chernikov error = 0; 1304b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1305b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1306b074b7bbSAlexander V. Chernikov if (no_n == NULL) 1307b074b7bbSAlexander V. Chernikov continue; 1308b074b7bbSAlexander V. Chernikov 1309b074b7bbSAlexander V. Chernikov if (no_n->type != no->type) { 1310b074b7bbSAlexander V. Chernikov error = EINVAL; 1311b074b7bbSAlexander V. Chernikov break; 1312b074b7bbSAlexander V. Chernikov } 1313b074b7bbSAlexander V. Chernikov 1314b074b7bbSAlexander V. Chernikov } 1315b074b7bbSAlexander V. Chernikov 1316b074b7bbSAlexander V. Chernikov if (error != 0) { 1317b074b7bbSAlexander V. Chernikov /* 1318b074b7bbSAlexander V. Chernikov * Someone has allocated table with different table type. 1319b074b7bbSAlexander V. Chernikov * We have to rollback everything. 1320b074b7bbSAlexander V. Chernikov */ 1321b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1322b074b7bbSAlexander V. Chernikov 1323b074b7bbSAlexander V. Chernikov goto free; 1324b074b7bbSAlexander V. Chernikov } 1325b074b7bbSAlexander V. Chernikov 1326b074b7bbSAlexander V. Chernikov 1327b074b7bbSAlexander V. Chernikov /* 13289f7d47b0SAlexander V. Chernikov * Attach new tables. 13299f7d47b0SAlexander V. Chernikov * We need to set table pointers for each new table, 1330b074b7bbSAlexander V. Chernikov * so we have to acquire main WLOCK. 1331b074b7bbSAlexander V. Chernikov */ 1332b074b7bbSAlexander V. Chernikov IPFW_WLOCK(chain); 1333b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1334b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1335b074b7bbSAlexander V. Chernikov if (no_n != NULL) { 1336b074b7bbSAlexander V. Chernikov /* Increase refcount for existing table */ 1337b074b7bbSAlexander V. Chernikov no_n->refcnt++; 1338b074b7bbSAlexander V. Chernikov /* Keep oib array in sync: update kindx */ 1339b074b7bbSAlexander V. Chernikov for (p = oib; p < pidx; p++) { 1340b074b7bbSAlexander V. Chernikov if (p->kidx == no->kidx) { 1341b074b7bbSAlexander V. Chernikov p->kidx = no_n->kidx; 1342b074b7bbSAlexander V. Chernikov break; 1343b074b7bbSAlexander V. Chernikov } 1344b074b7bbSAlexander V. Chernikov } 1345b074b7bbSAlexander V. Chernikov 1346b074b7bbSAlexander V. Chernikov continue; 1347b074b7bbSAlexander V. Chernikov } 1348b074b7bbSAlexander V. Chernikov 1349b074b7bbSAlexander V. Chernikov /* New table. Attach to runtime hash */ 1350b074b7bbSAlexander V. Chernikov TAILQ_REMOVE(&nh, no, nn_next); 1351b074b7bbSAlexander V. Chernikov 1352b074b7bbSAlexander V. Chernikov link_table(chain, (struct table_config *)no); 1353b074b7bbSAlexander V. Chernikov } 1354b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(chain); 13559f7d47b0SAlexander V. Chernikov } 1356b074b7bbSAlexander V. Chernikov 1357b074b7bbSAlexander V. Chernikov /* Perform rule rewrite */ 1358b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 1359b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 1360b074b7bbSAlexander V. Chernikov cmdlen = 0; 1361b074b7bbSAlexander V. Chernikov pidx = oib; 1362b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1363b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1364b074b7bbSAlexander V. Chernikov 1365b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &uidx, &type) != 0) 1366b074b7bbSAlexander V. Chernikov continue; 1367b074b7bbSAlexander V. Chernikov update_table_opcode(cmd, pidx->kidx); 1368b074b7bbSAlexander V. Chernikov pidx++; 1369b074b7bbSAlexander V. Chernikov } 1370b074b7bbSAlexander V. Chernikov 1371b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1372b074b7bbSAlexander V. Chernikov 1373b074b7bbSAlexander V. Chernikov error = 0; 1374b074b7bbSAlexander V. Chernikov 1375b074b7bbSAlexander V. Chernikov /* 1376b074b7bbSAlexander V. Chernikov * Stage 4: free resources 1377b074b7bbSAlexander V. Chernikov */ 1378b074b7bbSAlexander V. Chernikov free: 1379b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) 1380b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 1381b074b7bbSAlexander V. Chernikov 1382b074b7bbSAlexander V. Chernikov if (oib != ci->obuf) 1383b074b7bbSAlexander V. Chernikov free(oib, M_IPFW); 1384b074b7bbSAlexander V. Chernikov 1385b074b7bbSAlexander V. Chernikov return (error); 1386b074b7bbSAlexander V. Chernikov } 1387b074b7bbSAlexander V. Chernikov 1388b074b7bbSAlexander V. Chernikov /* 1389b074b7bbSAlexander V. Chernikov * Remove references from every table used in @rule. 1390b074b7bbSAlexander V. Chernikov */ 1391b074b7bbSAlexander V. Chernikov void 1392b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule) 1393b074b7bbSAlexander V. Chernikov { 1394b074b7bbSAlexander V. Chernikov int cmdlen, l; 1395b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1396b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1397b074b7bbSAlexander V. Chernikov struct named_object *no; 1398b074b7bbSAlexander V. Chernikov uint32_t set; 1399b074b7bbSAlexander V. Chernikov uint16_t kidx; 1400b074b7bbSAlexander V. Chernikov uint8_t type; 1401b074b7bbSAlexander V. Chernikov 1402b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1403b074b7bbSAlexander V. Chernikov 1404b074b7bbSAlexander V. Chernikov set = TABLE_SET(rule->set); 1405b074b7bbSAlexander V. Chernikov 1406b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1407b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1408b074b7bbSAlexander V. Chernikov cmdlen = 0; 1409b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1410b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1411b074b7bbSAlexander V. Chernikov 1412b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1413b074b7bbSAlexander V. Chernikov continue; 1414b074b7bbSAlexander V. Chernikov 1415b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_idx(ni, set, kidx); 1416b074b7bbSAlexander V. Chernikov 1417b074b7bbSAlexander V. Chernikov KASSERT(no != NULL, ("table id %d not found", kidx)); 1418b074b7bbSAlexander V. Chernikov KASSERT(no->type == type, ("wrong type %d (%d) for table id %d", 1419b074b7bbSAlexander V. Chernikov no->type, type, kidx)); 1420b074b7bbSAlexander V. Chernikov KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 1421b074b7bbSAlexander V. Chernikov kidx, no->refcnt)); 1422b074b7bbSAlexander V. Chernikov 1423b074b7bbSAlexander V. Chernikov no->refcnt--; 1424b074b7bbSAlexander V. Chernikov } 1425b074b7bbSAlexander V. Chernikov } 1426b074b7bbSAlexander V. Chernikov 1427b074b7bbSAlexander V. Chernikov 1428b074b7bbSAlexander V. Chernikov /* 1429b074b7bbSAlexander V. Chernikov * Removes table bindings for every rule in rule chain @head. 1430b074b7bbSAlexander V. Chernikov */ 1431b074b7bbSAlexander V. Chernikov void 1432b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head) 1433b074b7bbSAlexander V. Chernikov { 1434b074b7bbSAlexander V. Chernikov struct ip_fw *rule; 1435b074b7bbSAlexander V. Chernikov 1436b074b7bbSAlexander V. Chernikov while ((rule = head) != NULL) { 1437b074b7bbSAlexander V. Chernikov head = head->x_next; 1438b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(chain, rule); 1439b074b7bbSAlexander V. Chernikov } 1440b074b7bbSAlexander V. Chernikov } 1441b074b7bbSAlexander V. Chernikov 1442b074b7bbSAlexander V. Chernikov 14433b3a8eb9SGleb Smirnoff /* end of file */ 1444