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 443b3a8eb9SGleb Smirnoff #include <sys/param.h> 453b3a8eb9SGleb Smirnoff #include <sys/systm.h> 463b3a8eb9SGleb Smirnoff #include <sys/malloc.h> 473b3a8eb9SGleb Smirnoff #include <sys/kernel.h> 483b3a8eb9SGleb Smirnoff #include <sys/lock.h> 493b3a8eb9SGleb Smirnoff #include <sys/rwlock.h> 503b3a8eb9SGleb Smirnoff #include <sys/socket.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. 719f7d47b0SAlexander V. Chernikov * `ftype` is pure userland field helping to properly format table data 729f7d47b0SAlexander V. Chernikov * e.g. "value is IPv4 nexthop" or "key is port number" 73b074b7bbSAlexander V. Chernikov * 74b074b7bbSAlexander V. Chernikov */ 75b074b7bbSAlexander V. Chernikov struct table_config { 76b074b7bbSAlexander V. Chernikov struct named_object no; 77b074b7bbSAlexander V. Chernikov uint8_t ftype; /* format table type */ 78b074b7bbSAlexander V. Chernikov uint8_t linked; /* 1 if already linked */ 799f7d47b0SAlexander V. Chernikov uint16_t spare0; 80b074b7bbSAlexander V. Chernikov uint32_t count; /* Number of records */ 81b074b7bbSAlexander V. Chernikov char tablename[64]; /* table name */ 829f7d47b0SAlexander V. Chernikov struct table_algo *ta; /* Callbacks for given algo */ 839f7d47b0SAlexander V. Chernikov void *astate; /* algorithm state */ 849f7d47b0SAlexander V. Chernikov struct table_info ti; /* data to put to table_info */ 85b074b7bbSAlexander V. Chernikov }; 86b074b7bbSAlexander V. Chernikov #define TABLE_SET(set) ((V_fw_tables_sets != 0) ? set : 0) 87b074b7bbSAlexander V. Chernikov 88b074b7bbSAlexander V. Chernikov struct tables_config { 89b074b7bbSAlexander V. Chernikov struct namedobj_instance *namehash; 909f7d47b0SAlexander V. Chernikov int algo_count; 919f7d47b0SAlexander V. Chernikov struct table_algo *algo[256]; 92b074b7bbSAlexander V. Chernikov }; 93b074b7bbSAlexander V. Chernikov 94b074b7bbSAlexander V. Chernikov static struct table_config *find_table(struct namedobj_instance *ni, 95b074b7bbSAlexander V. Chernikov struct tid_info *ti); 96b074b7bbSAlexander V. Chernikov static struct table_config *alloc_table_config(struct namedobj_instance *ni, 979f7d47b0SAlexander V. Chernikov struct tid_info *ti, struct table_algo *ta); 98b074b7bbSAlexander V. Chernikov static void free_table_config(struct namedobj_instance *ni, 99b074b7bbSAlexander V. Chernikov struct table_config *tc); 100b074b7bbSAlexander V. Chernikov static void link_table(struct ip_fw_chain *chain, struct table_config *tc); 101b074b7bbSAlexander V. Chernikov static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc); 102b074b7bbSAlexander V. Chernikov static void free_table_state(void **state, void **xstate, uint8_t type); 103b074b7bbSAlexander V. Chernikov 1049f7d47b0SAlexander V. Chernikov static struct table_algo *find_table_algo(struct tables_config *tableconf, 1059f7d47b0SAlexander V. Chernikov struct tid_info *ti); 106b074b7bbSAlexander V. Chernikov 107b074b7bbSAlexander V. Chernikov #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) 108b074b7bbSAlexander V. Chernikov #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) 1099f7d47b0SAlexander V. Chernikov #define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) 110b074b7bbSAlexander V. Chernikov 111b074b7bbSAlexander V. Chernikov 1123b3a8eb9SGleb Smirnoff 1133b3a8eb9SGleb Smirnoff int 114b074b7bbSAlexander V. Chernikov ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 115b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 1163b3a8eb9SGleb Smirnoff { 117b074b7bbSAlexander V. Chernikov struct table_config *tc, *tc_new; 1189f7d47b0SAlexander V. Chernikov struct table_algo *ta; 119b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 120b074b7bbSAlexander V. Chernikov uint16_t kidx; 1219f7d47b0SAlexander V. Chernikov int error; 1229f7d47b0SAlexander V. Chernikov char ta_buf[128]; 1233b3a8eb9SGleb Smirnoff 1249f7d47b0SAlexander V. Chernikov #if 0 125b074b7bbSAlexander V. Chernikov if (ti->uidx >= V_fw_tables_max) 1263b3a8eb9SGleb Smirnoff return (EINVAL); 1273b3a8eb9SGleb Smirnoff #endif 1289f7d47b0SAlexander V. Chernikov 1299f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1309f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1319f7d47b0SAlexander V. Chernikov 1329f7d47b0SAlexander V. Chernikov /* 1339f7d47b0SAlexander V. Chernikov * Find and reference existing table. 1349f7d47b0SAlexander V. Chernikov */ 1359f7d47b0SAlexander V. Chernikov ta = NULL; 1369f7d47b0SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1379f7d47b0SAlexander V. Chernikov /* check table type */ 1389f7d47b0SAlexander V. Chernikov if (tc->no.type != ti->type) { 1399f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1403b3a8eb9SGleb Smirnoff return (EINVAL); 1413b3a8eb9SGleb Smirnoff } 1423b3a8eb9SGleb Smirnoff 1439f7d47b0SAlexander V. Chernikov /* Reference and unlock */ 1449f7d47b0SAlexander V. Chernikov tc->no.refcnt++; 1459f7d47b0SAlexander V. Chernikov ta = tc->ta; 1469f7d47b0SAlexander V. Chernikov } 1479f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1483b3a8eb9SGleb Smirnoff 1499f7d47b0SAlexander V. Chernikov tc_new = NULL; 1509f7d47b0SAlexander V. Chernikov if (ta == NULL) { 1519f7d47b0SAlexander V. Chernikov /* Table not found. We have to create new one */ 1529f7d47b0SAlexander V. Chernikov if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti)) == NULL) 1539f7d47b0SAlexander V. Chernikov return (ENOTSUP); 1543b3a8eb9SGleb Smirnoff 1559f7d47b0SAlexander V. Chernikov tc_new = alloc_table_config(ni, ti, ta); 1569f7d47b0SAlexander V. Chernikov if (tc_new == NULL) 1579f7d47b0SAlexander V. Chernikov return (ENOMEM); 1589f7d47b0SAlexander V. Chernikov } 1593b3a8eb9SGleb Smirnoff 1609f7d47b0SAlexander V. Chernikov /* Prepare record (allocate memory) */ 1619f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 1629f7d47b0SAlexander V. Chernikov error = ta->prepare_add(tei, &ta_buf); 1639f7d47b0SAlexander V. Chernikov if (error != 0) { 1649f7d47b0SAlexander V. Chernikov if (tc_new != NULL) 1659f7d47b0SAlexander V. Chernikov free_table_config(ni, tc_new); 1669f7d47b0SAlexander V. Chernikov return (error); 1673b3a8eb9SGleb Smirnoff } 1683b3a8eb9SGleb Smirnoff 169b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1703b3a8eb9SGleb Smirnoff 171b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1723b3a8eb9SGleb Smirnoff 1739f7d47b0SAlexander V. Chernikov if (tc == NULL) { 1749f7d47b0SAlexander V. Chernikov /* Check if another table was allocated by other thread */ 175b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1769f7d47b0SAlexander V. Chernikov 1779f7d47b0SAlexander V. Chernikov /* 1789f7d47b0SAlexander V. Chernikov * Check if algoritm is the same since we've 1799f7d47b0SAlexander V. Chernikov * already allocated state using @ta algoritm 1809f7d47b0SAlexander V. Chernikov * callbacks. 1819f7d47b0SAlexander V. Chernikov */ 1829f7d47b0SAlexander V. Chernikov if (tc->ta != ta) { 183b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 184b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 1853b3a8eb9SGleb Smirnoff return (EINVAL); 1863b3a8eb9SGleb Smirnoff } 1873b3a8eb9SGleb Smirnoff } else { 1883b3a8eb9SGleb Smirnoff /* 1899f7d47b0SAlexander V. Chernikov * We're first to create this table. 190b074b7bbSAlexander V. Chernikov * Set tc_new to zero not to free it afterwards. 1913b3a8eb9SGleb Smirnoff */ 192b074b7bbSAlexander V. Chernikov tc = tc_new; 193b074b7bbSAlexander V. Chernikov tc_new = NULL; 194b074b7bbSAlexander V. Chernikov 195b074b7bbSAlexander V. Chernikov /* Allocate table index. */ 196b074b7bbSAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, ti->set, &kidx) != 0) { 197b074b7bbSAlexander V. Chernikov /* Index full. */ 198b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 199b074b7bbSAlexander V. Chernikov printf("Unable to allocate index for table %s." 200b074b7bbSAlexander V. Chernikov " Consider increasing " 201b074b7bbSAlexander V. Chernikov "net.inet.ip.fw.tables_max", 202b074b7bbSAlexander V. Chernikov tc->no.name); 203b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 204b074b7bbSAlexander V. Chernikov return (EBUSY); 2053b3a8eb9SGleb Smirnoff } 206b074b7bbSAlexander V. Chernikov /* Save kidx */ 207b074b7bbSAlexander V. Chernikov tc->no.kidx = kidx; 208b074b7bbSAlexander V. Chernikov } 209b074b7bbSAlexander V. Chernikov } else { 2109f7d47b0SAlexander V. Chernikov /* Drop reference we've used in first search */ 2119f7d47b0SAlexander V. Chernikov tc->no.refcnt--; 212b074b7bbSAlexander V. Chernikov } 213b074b7bbSAlexander V. Chernikov 214b074b7bbSAlexander V. Chernikov /* We've got valid table in @tc. Let's add data */ 2159f7d47b0SAlexander V. Chernikov kidx = tc->no.kidx; 2169f7d47b0SAlexander V. Chernikov ta = tc->ta; 2179f7d47b0SAlexander V. Chernikov 218b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 219b074b7bbSAlexander V. Chernikov 220b074b7bbSAlexander V. Chernikov if (tc->linked == 0) { 221b074b7bbSAlexander V. Chernikov link_table(ch, tc); 222b074b7bbSAlexander V. Chernikov } 223b074b7bbSAlexander V. Chernikov 2249f7d47b0SAlexander V. Chernikov error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); 2253b3a8eb9SGleb Smirnoff 2263b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2279f7d47b0SAlexander V. Chernikov 2289f7d47b0SAlexander V. Chernikov if (error == 0) 2299f7d47b0SAlexander V. Chernikov tc->count++; 2309f7d47b0SAlexander V. Chernikov 231b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 232b074b7bbSAlexander V. Chernikov 233b074b7bbSAlexander V. Chernikov if (tc_new != NULL) 234b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 2353b3a8eb9SGleb Smirnoff 2369f7d47b0SAlexander V. Chernikov if (error != 0) 2379f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 238b074b7bbSAlexander V. Chernikov 2399f7d47b0SAlexander V. Chernikov return (error); 2403b3a8eb9SGleb Smirnoff } 2413b3a8eb9SGleb Smirnoff 2423b3a8eb9SGleb Smirnoff int 243b074b7bbSAlexander V. Chernikov ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 244b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 2453b3a8eb9SGleb Smirnoff { 246b074b7bbSAlexander V. Chernikov struct table_config *tc; 2479f7d47b0SAlexander V. Chernikov struct table_algo *ta; 248b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 249b074b7bbSAlexander V. Chernikov uint16_t kidx; 2509f7d47b0SAlexander V. Chernikov int error; 2519f7d47b0SAlexander V. Chernikov char ta_buf[128]; 2523b3a8eb9SGleb Smirnoff 2539f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 254b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 255b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 2569f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2573b3a8eb9SGleb Smirnoff return (ESRCH); 2583b3a8eb9SGleb Smirnoff } 2593b3a8eb9SGleb Smirnoff 260b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 2619f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2623b3a8eb9SGleb Smirnoff return (EINVAL); 2633b3a8eb9SGleb Smirnoff } 2649f7d47b0SAlexander V. Chernikov 2659f7d47b0SAlexander V. Chernikov ta = tc->ta; 2669f7d47b0SAlexander V. Chernikov 2679f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 2689f7d47b0SAlexander V. Chernikov if ((error = ta->prepare_del(tei, &ta_buf)) != 0) { 2699f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2709f7d47b0SAlexander V. Chernikov return (error); 2719f7d47b0SAlexander V. Chernikov } 2729f7d47b0SAlexander V. Chernikov 273b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 274b074b7bbSAlexander V. Chernikov 275b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 2769f7d47b0SAlexander V. Chernikov error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); 2773b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2783b3a8eb9SGleb Smirnoff 2799f7d47b0SAlexander V. Chernikov if (error == 0) 2809f7d47b0SAlexander V. Chernikov tc->count--; 281b074b7bbSAlexander V. Chernikov 2829f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2833b3a8eb9SGleb Smirnoff 2849f7d47b0SAlexander V. Chernikov if (error != 0) 2859f7d47b0SAlexander V. Chernikov return (error); 2863b3a8eb9SGleb Smirnoff 2879f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 2883b3a8eb9SGleb Smirnoff return (0); 2893b3a8eb9SGleb Smirnoff } 2903b3a8eb9SGleb Smirnoff 291b074b7bbSAlexander V. Chernikov /* 2929f7d47b0SAlexander V. Chernikov * Flushes all entries in given table. 293b074b7bbSAlexander V. Chernikov */ 2943b3a8eb9SGleb Smirnoff int 295b074b7bbSAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti) 2963b3a8eb9SGleb Smirnoff { 297b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 298b074b7bbSAlexander V. Chernikov struct table_config *tc; 2999f7d47b0SAlexander V. Chernikov struct table_algo *ta; 3009f7d47b0SAlexander V. Chernikov struct table_info ti_old, ti_new, *tablestate; 3019f7d47b0SAlexander V. Chernikov void *astate_old, *astate_new; 302b074b7bbSAlexander V. Chernikov int error; 303b074b7bbSAlexander V. Chernikov uint16_t kidx; 3043b3a8eb9SGleb Smirnoff 3053b3a8eb9SGleb Smirnoff /* 3069f7d47b0SAlexander V. Chernikov * Stage 1: save table algoritm. 307b074b7bbSAlexander V. Chernikov * Reference found table to ensure it won't disappear. 3083b3a8eb9SGleb Smirnoff */ 309b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 310b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 311b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 312b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 313b074b7bbSAlexander V. Chernikov return (ESRCH); 314b074b7bbSAlexander V. Chernikov } 3159f7d47b0SAlexander V. Chernikov ta = tc->ta; 316b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 317b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3183b3a8eb9SGleb Smirnoff 319b074b7bbSAlexander V. Chernikov /* 3209f7d47b0SAlexander V. Chernikov * Stage 2: allocate new table instance using same algo. 321b074b7bbSAlexander V. Chernikov */ 3229f7d47b0SAlexander V. Chernikov memset(&ti_new, 0, sizeof(struct table_info)); 3239f7d47b0SAlexander V. Chernikov if ((error = ta->init(&astate_new, &ti_new)) != 0) { 324b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 325b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 326b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 327b074b7bbSAlexander V. Chernikov return (error); 328b074b7bbSAlexander V. Chernikov } 329b074b7bbSAlexander V. Chernikov 330b074b7bbSAlexander V. Chernikov /* 331b074b7bbSAlexander V. Chernikov * Stage 3: swap old state pointers with newly-allocated ones. 332b074b7bbSAlexander V. Chernikov * Decrease refcount. 333b074b7bbSAlexander V. Chernikov */ 334b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 335b074b7bbSAlexander V. Chernikov 336b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 337b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 3389f7d47b0SAlexander V. Chernikov tablestate = (struct table_info *)ch->tablestate; 339b074b7bbSAlexander V. Chernikov 3409f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 3419f7d47b0SAlexander V. Chernikov ti_old = tablestate[kidx]; 3429f7d47b0SAlexander V. Chernikov tablestate[kidx] = ti_new; 3439f7d47b0SAlexander V. Chernikov IPFW_WUNLOCK(ch); 344b074b7bbSAlexander V. Chernikov 3459f7d47b0SAlexander V. Chernikov astate_old = tc->astate; 3469f7d47b0SAlexander V. Chernikov tc->astate = astate_new; 3479f7d47b0SAlexander V. Chernikov tc->ti = ti_new; 3489f7d47b0SAlexander V. Chernikov tc->count = 0; 349b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 350b074b7bbSAlexander V. Chernikov 351b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3523b3a8eb9SGleb Smirnoff 353b074b7bbSAlexander V. Chernikov /* 354b074b7bbSAlexander V. Chernikov * Stage 4: perform real flush. 355b074b7bbSAlexander V. Chernikov */ 3569f7d47b0SAlexander V. Chernikov ta->destroy(astate_old, &ti_old); 3573b3a8eb9SGleb Smirnoff 3583b3a8eb9SGleb Smirnoff return (0); 3593b3a8eb9SGleb Smirnoff } 3603b3a8eb9SGleb Smirnoff 361b074b7bbSAlexander V. Chernikov /* 3629f7d47b0SAlexander V. Chernikov * Destroys table specified by @ti. 363b074b7bbSAlexander V. Chernikov */ 364b074b7bbSAlexander V. Chernikov int 3659f7d47b0SAlexander V. Chernikov ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) 366b074b7bbSAlexander V. Chernikov { 367b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 368b074b7bbSAlexander V. Chernikov struct table_config *tc; 369b074b7bbSAlexander V. Chernikov 370b074b7bbSAlexander V. Chernikov ti->set = TABLE_SET(ti->set); 371b074b7bbSAlexander V. Chernikov 372b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 373b074b7bbSAlexander V. Chernikov 374b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 375b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 376b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 377b074b7bbSAlexander V. Chernikov return (ESRCH); 378b074b7bbSAlexander V. Chernikov } 379b074b7bbSAlexander V. Chernikov 3809f7d47b0SAlexander V. Chernikov /* Do not permit destroying referenced tables */ 3819f7d47b0SAlexander V. Chernikov if (tc->no.refcnt > 0) { 382b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 383b074b7bbSAlexander V. Chernikov return (EBUSY); 384b074b7bbSAlexander V. Chernikov } 385b074b7bbSAlexander V. Chernikov 386b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 387b074b7bbSAlexander V. Chernikov unlink_table(ch, tc); 388b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 389b074b7bbSAlexander V. Chernikov 390b074b7bbSAlexander V. Chernikov /* Free obj index */ 391b074b7bbSAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, tc->no.set, tc->no.kidx) != 0) 392b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 393b074b7bbSAlexander V. Chernikov tc->no.kidx, tc->tablename); 394b074b7bbSAlexander V. Chernikov 395b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 396b074b7bbSAlexander V. Chernikov 397b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 398b074b7bbSAlexander V. Chernikov 399b074b7bbSAlexander V. Chernikov return (0); 400b074b7bbSAlexander V. Chernikov } 401b074b7bbSAlexander V. Chernikov 402b074b7bbSAlexander V. Chernikov static void 403b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, 404b074b7bbSAlexander V. Chernikov void *arg) 405b074b7bbSAlexander V. Chernikov { 406b074b7bbSAlexander V. Chernikov 407b074b7bbSAlexander V. Chernikov unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); 408b074b7bbSAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, no->set, no->kidx) != 0) 409b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 410b074b7bbSAlexander V. Chernikov no->kidx, no->name); 411b074b7bbSAlexander V. Chernikov free_table_config(ni, (struct table_config *)no); 412b074b7bbSAlexander V. Chernikov } 413b074b7bbSAlexander V. Chernikov 4143b3a8eb9SGleb Smirnoff void 4153b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch) 4163b3a8eb9SGleb Smirnoff { 4173b3a8eb9SGleb Smirnoff 418b074b7bbSAlexander V. Chernikov /* Remove all tables from working set */ 419b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 420b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 421b074b7bbSAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); 422b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 423b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 4243b3a8eb9SGleb Smirnoff 4253b3a8eb9SGleb Smirnoff /* Free pointers itself */ 4269f7d47b0SAlexander V. Chernikov free(ch->tablestate, M_IPFW); 4279f7d47b0SAlexander V. Chernikov 4289f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(ch); 429b074b7bbSAlexander V. Chernikov 430b074b7bbSAlexander V. Chernikov ipfw_objhash_destroy(CHAIN_TO_NI(ch)); 431b074b7bbSAlexander V. Chernikov free(CHAIN_TO_TCFG(ch), M_IPFW); 4323b3a8eb9SGleb Smirnoff } 4333b3a8eb9SGleb Smirnoff 4343b3a8eb9SGleb Smirnoff int 4353b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch) 4363b3a8eb9SGleb Smirnoff { 437b074b7bbSAlexander V. Chernikov struct tables_config *tcfg; 438b074b7bbSAlexander V. Chernikov 4393b3a8eb9SGleb Smirnoff /* Allocate pointers */ 4409f7d47b0SAlexander V. Chernikov ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), 4419f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 442b074b7bbSAlexander V. Chernikov 443b074b7bbSAlexander V. Chernikov tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); 444b074b7bbSAlexander V. Chernikov tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); 445b074b7bbSAlexander V. Chernikov ch->tblcfg = tcfg; 446b074b7bbSAlexander V. Chernikov 4479f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(ch); 4489f7d47b0SAlexander V. Chernikov 4493b3a8eb9SGleb Smirnoff return (0); 4503b3a8eb9SGleb Smirnoff } 4513b3a8eb9SGleb Smirnoff 4523b3a8eb9SGleb Smirnoff int 4533b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) 4543b3a8eb9SGleb Smirnoff { 4553b3a8eb9SGleb Smirnoff unsigned int ntables_old, tbl; 456b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 4579f7d47b0SAlexander V. Chernikov void *new_idx, *old_tablestate, *tablestate; 458b074b7bbSAlexander V. Chernikov int new_blocks; 4593b3a8eb9SGleb Smirnoff 4603b3a8eb9SGleb Smirnoff /* Check new value for validity */ 4613b3a8eb9SGleb Smirnoff if (ntables > IPFW_TABLES_MAX) 4623b3a8eb9SGleb Smirnoff ntables = IPFW_TABLES_MAX; 4633b3a8eb9SGleb Smirnoff 4643b3a8eb9SGleb Smirnoff /* Allocate new pointers */ 4659f7d47b0SAlexander V. Chernikov tablestate = malloc(ntables * sizeof(struct table_info), 4669f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 4679f7d47b0SAlexander V. Chernikov 468b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); 4693b3a8eb9SGleb Smirnoff 4709f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 4713b3a8eb9SGleb Smirnoff 4723b3a8eb9SGleb Smirnoff tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables; 473b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 474b074b7bbSAlexander V. Chernikov 4759f7d47b0SAlexander V. Chernikov /* Temporary restrict decreasing max_tables */ 4769f7d47b0SAlexander V. Chernikov if (ntables < V_fw_tables_max) { 4779f7d47b0SAlexander V. Chernikov 4789f7d47b0SAlexander V. Chernikov /* 4799f7d47b0SAlexander V. Chernikov * FIXME: Check if we really can shrink 4809f7d47b0SAlexander V. Chernikov */ 4819f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 482b074b7bbSAlexander V. Chernikov return (EINVAL); 483b074b7bbSAlexander V. Chernikov } 4843b3a8eb9SGleb Smirnoff 4859f7d47b0SAlexander V. Chernikov /* Copy table info/indices */ 4869f7d47b0SAlexander V. Chernikov memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl); 4879f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks); 4883b3a8eb9SGleb Smirnoff 4899f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 4909f7d47b0SAlexander V. Chernikov 4919f7d47b0SAlexander V. Chernikov /* Change pointers */ 4929f7d47b0SAlexander V. Chernikov old_tablestate = ch->tablestate; 4939f7d47b0SAlexander V. Chernikov ch->tablestate = tablestate; 4949f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks); 4953b3a8eb9SGleb Smirnoff 4963b3a8eb9SGleb Smirnoff ntables_old = V_fw_tables_max; 4973b3a8eb9SGleb Smirnoff V_fw_tables_max = ntables; 4983b3a8eb9SGleb Smirnoff 4993b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 5009f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 5013b3a8eb9SGleb Smirnoff 5023b3a8eb9SGleb Smirnoff /* Free old pointers */ 5039f7d47b0SAlexander V. Chernikov free(old_tablestate, M_IPFW); 504b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 5053b3a8eb9SGleb Smirnoff 5063b3a8eb9SGleb Smirnoff return (0); 5073b3a8eb9SGleb Smirnoff } 5083b3a8eb9SGleb Smirnoff 5093b3a8eb9SGleb Smirnoff int 5103b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 5113b3a8eb9SGleb Smirnoff uint32_t *val) 5123b3a8eb9SGleb Smirnoff { 5139f7d47b0SAlexander V. Chernikov struct table_info *ti; 5143b3a8eb9SGleb Smirnoff 5159f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 5169f7d47b0SAlexander V. Chernikov 5179f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, &addr, sizeof(in_addr_t), val)); 5183b3a8eb9SGleb Smirnoff } 5199f7d47b0SAlexander V. Chernikov 5209f7d47b0SAlexander V. Chernikov int 5219f7d47b0SAlexander V. Chernikov ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, 5229f7d47b0SAlexander V. Chernikov void *paddr, uint32_t *val) 5239f7d47b0SAlexander V. Chernikov { 5249f7d47b0SAlexander V. Chernikov struct table_info *ti; 5259f7d47b0SAlexander V. Chernikov 5269f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 5279f7d47b0SAlexander V. Chernikov 5289f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, paddr, plen, val)); 5299f7d47b0SAlexander V. Chernikov } 5309f7d47b0SAlexander V. Chernikov 5319f7d47b0SAlexander V. Chernikov /* 5329f7d47b0SAlexander V. Chernikov * Info/List/dump support for tables. 5339f7d47b0SAlexander V. Chernikov * 5349f7d47b0SAlexander V. Chernikov */ 5359f7d47b0SAlexander V. Chernikov 5369f7d47b0SAlexander V. Chernikov static void 5379f7d47b0SAlexander V. Chernikov export_table_info(struct table_config *tc, ipfw_xtable_info *i) 5389f7d47b0SAlexander V. Chernikov { 5399f7d47b0SAlexander V. Chernikov 5409f7d47b0SAlexander V. Chernikov i->type = tc->no.type; 5419f7d47b0SAlexander V. Chernikov i->ftype = tc->ftype; 5429f7d47b0SAlexander V. Chernikov i->atype = tc->ta->idx; 5439f7d47b0SAlexander V. Chernikov i->set = tc->no.set; 5449f7d47b0SAlexander V. Chernikov i->kidx = tc->no.kidx; 5459f7d47b0SAlexander V. Chernikov i->refcnt = tc->no.refcnt; 5469f7d47b0SAlexander V. Chernikov i->count = tc->count; 5479f7d47b0SAlexander V. Chernikov i->size = tc->count * sizeof(ipfw_table_xentry); 5489f7d47b0SAlexander V. Chernikov if (tc->count > 0) 5499f7d47b0SAlexander V. Chernikov i->size += sizeof(ipfw_xtable); 5509f7d47b0SAlexander V. Chernikov strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); 5519f7d47b0SAlexander V. Chernikov } 5529f7d47b0SAlexander V. Chernikov 5539f7d47b0SAlexander V. Chernikov int 5549f7d47b0SAlexander V. Chernikov ipfw_count_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh) 5559f7d47b0SAlexander V. Chernikov { 5569f7d47b0SAlexander V. Chernikov uint32_t count; 5579f7d47b0SAlexander V. Chernikov 5589f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 5599f7d47b0SAlexander V. Chernikov 5609f7d47b0SAlexander V. Chernikov olh->count = count; 5619f7d47b0SAlexander V. Chernikov olh->size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 5629f7d47b0SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 5639f7d47b0SAlexander V. Chernikov 5643b3a8eb9SGleb Smirnoff return (0); 5653b3a8eb9SGleb Smirnoff } 5663b3a8eb9SGleb Smirnoff 5673b3a8eb9SGleb Smirnoff int 5689f7d47b0SAlexander V. Chernikov ipfw_describe_table(struct ip_fw_chain *ch, struct tid_info *ti, 5699f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i) 5703b3a8eb9SGleb Smirnoff { 5719f7d47b0SAlexander V. Chernikov struct table_config *tc; 5723b3a8eb9SGleb Smirnoff 5739f7d47b0SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 5749f7d47b0SAlexander V. Chernikov return (ESRCH); 5753b3a8eb9SGleb Smirnoff 5769f7d47b0SAlexander V. Chernikov export_table_info(tc, i); 5773b3a8eb9SGleb Smirnoff 5783b3a8eb9SGleb Smirnoff return (0); 5793b3a8eb9SGleb Smirnoff } 5803b3a8eb9SGleb Smirnoff 5819f7d47b0SAlexander V. Chernikov static void 5829f7d47b0SAlexander V. Chernikov export_table_internal(struct namedobj_instance *ni, struct named_object *no, 5839f7d47b0SAlexander V. Chernikov void *arg) 5843b3a8eb9SGleb Smirnoff { 5859f7d47b0SAlexander V. Chernikov ipfw_obj_lheader *olh; 5869f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i; 5873b3a8eb9SGleb Smirnoff 5889f7d47b0SAlexander V. Chernikov olh = (ipfw_obj_lheader *)arg; 5899f7d47b0SAlexander V. Chernikov i = (ipfw_xtable_info *)(caddr_t)(olh + 1) + olh->count; 5909f7d47b0SAlexander V. Chernikov olh->count++; 5919f7d47b0SAlexander V. Chernikov 5929f7d47b0SAlexander V. Chernikov export_table_info((struct table_config *)no, i); 5939f7d47b0SAlexander V. Chernikov } 5949f7d47b0SAlexander V. Chernikov 5959f7d47b0SAlexander V. Chernikov int 5969f7d47b0SAlexander V. Chernikov ipfw_list_tables(struct ip_fw_chain *ch, struct tid_info *ti, 5979f7d47b0SAlexander V. Chernikov ipfw_obj_lheader *olh) 5989f7d47b0SAlexander V. Chernikov { 5999f7d47b0SAlexander V. Chernikov uint32_t size; 6009f7d47b0SAlexander V. Chernikov uint32_t count; 6019f7d47b0SAlexander V. Chernikov 6029f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 6039f7d47b0SAlexander V. Chernikov size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 6049f7d47b0SAlexander V. Chernikov if (size > olh->size) 6059f7d47b0SAlexander V. Chernikov return (ENOMEM); 6069f7d47b0SAlexander V. Chernikov 6079f7d47b0SAlexander V. Chernikov olh->count = 0; 6089f7d47b0SAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, olh); 6099f7d47b0SAlexander V. Chernikov 6109f7d47b0SAlexander V. Chernikov olh->count = count; 6119f7d47b0SAlexander V. Chernikov olh->size = size; 6129f7d47b0SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 6139f7d47b0SAlexander V. Chernikov 6143b3a8eb9SGleb Smirnoff return (0); 6153b3a8eb9SGleb Smirnoff } 6163b3a8eb9SGleb Smirnoff 6173b3a8eb9SGleb Smirnoff int 618b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 6193b3a8eb9SGleb Smirnoff { 620b074b7bbSAlexander V. Chernikov struct table_config *tc; 6213b3a8eb9SGleb Smirnoff 622b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 623b074b7bbSAlexander V. Chernikov return (ESRCH); 6249f7d47b0SAlexander V. Chernikov *cnt = tc->count; 6253b3a8eb9SGleb Smirnoff return (0); 6263b3a8eb9SGleb Smirnoff } 6273b3a8eb9SGleb Smirnoff 6289f7d47b0SAlexander V. Chernikov 6299f7d47b0SAlexander V. Chernikov int 6309f7d47b0SAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 6313b3a8eb9SGleb Smirnoff { 6329f7d47b0SAlexander V. Chernikov struct table_config *tc; 6339f7d47b0SAlexander V. Chernikov 6349f7d47b0SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 6359f7d47b0SAlexander V. Chernikov return (0); /* 'table all list' requires success */ 6369f7d47b0SAlexander V. Chernikov *cnt = tc->count * sizeof(ipfw_table_xentry); 6379f7d47b0SAlexander V. Chernikov if (tc->count > 0) 6389f7d47b0SAlexander V. Chernikov *cnt += sizeof(ipfw_xtable); 6399f7d47b0SAlexander V. Chernikov return (0); 6409f7d47b0SAlexander V. Chernikov } 6419f7d47b0SAlexander V. Chernikov 6429f7d47b0SAlexander V. Chernikov struct dump_args { 6439f7d47b0SAlexander V. Chernikov struct table_info *ti; 6449f7d47b0SAlexander V. Chernikov struct table_config *tc; 6459f7d47b0SAlexander V. Chernikov ipfw_table *tbl; 6469f7d47b0SAlexander V. Chernikov ipfw_xtable *xtbl; 6479f7d47b0SAlexander V. Chernikov }; 6489f7d47b0SAlexander V. Chernikov 6499f7d47b0SAlexander V. Chernikov static int 6509f7d47b0SAlexander V. Chernikov dump_table_entry(void *e, void *arg) 6519f7d47b0SAlexander V. Chernikov { 6529f7d47b0SAlexander V. Chernikov ipfw_table *tbl; 6539f7d47b0SAlexander V. Chernikov struct dump_args *da; 6549f7d47b0SAlexander V. Chernikov struct table_config *tc; 6559f7d47b0SAlexander V. Chernikov struct table_algo *ta; 6563b3a8eb9SGleb Smirnoff ipfw_table_entry *ent; 6573b3a8eb9SGleb Smirnoff 6589f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 6599f7d47b0SAlexander V. Chernikov 6609f7d47b0SAlexander V. Chernikov tbl = da->tbl; 6619f7d47b0SAlexander V. Chernikov tc = da->tc; 6629f7d47b0SAlexander V. Chernikov ta = tc->ta; 6639f7d47b0SAlexander V. Chernikov 6649f7d47b0SAlexander V. Chernikov /* Out of memory, returning */ 6653b3a8eb9SGleb Smirnoff if (tbl->cnt == tbl->size) 6663b3a8eb9SGleb Smirnoff return (1); 6673b3a8eb9SGleb Smirnoff ent = &tbl->ent[tbl->cnt]; 6683b3a8eb9SGleb Smirnoff ent->tbl = tbl->tbl; 6693b3a8eb9SGleb Smirnoff tbl->cnt++; 6709f7d47b0SAlexander V. Chernikov 6719f7d47b0SAlexander V. Chernikov return (ta->dump_entry(tc->astate, da->ti, e, ent)); 6723b3a8eb9SGleb Smirnoff } 6733b3a8eb9SGleb Smirnoff 6743b3a8eb9SGleb Smirnoff int 675b074b7bbSAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_table *tbl) 6763b3a8eb9SGleb Smirnoff { 677b074b7bbSAlexander V. Chernikov struct table_config *tc; 6789f7d47b0SAlexander V. Chernikov struct table_algo *ta; 6799f7d47b0SAlexander V. Chernikov struct dump_args da; 6803b3a8eb9SGleb Smirnoff 6813b3a8eb9SGleb Smirnoff tbl->cnt = 0; 6823b3a8eb9SGleb Smirnoff 683b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 684b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 6859f7d47b0SAlexander V. Chernikov 6869f7d47b0SAlexander V. Chernikov ta = tc->ta; 6879f7d47b0SAlexander V. Chernikov 6889f7d47b0SAlexander V. Chernikov if (ta->dump_entry == NULL) 6899f7d47b0SAlexander V. Chernikov return (0); /* Legacy dump support is not necessary */ 6909f7d47b0SAlexander V. Chernikov 6919f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 6929f7d47b0SAlexander V. Chernikov da.tc = tc; 6939f7d47b0SAlexander V. Chernikov da.tbl = tbl; 6949f7d47b0SAlexander V. Chernikov 6959f7d47b0SAlexander V. Chernikov tbl->cnt = 0; 6969f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_entry, &da); 6979f7d47b0SAlexander V. Chernikov 6983b3a8eb9SGleb Smirnoff return (0); 6993b3a8eb9SGleb Smirnoff } 7003b3a8eb9SGleb Smirnoff 7013b3a8eb9SGleb Smirnoff 7023b3a8eb9SGleb Smirnoff static int 7039f7d47b0SAlexander V. Chernikov dump_table_xentry(void *e, void *arg) 7043b3a8eb9SGleb Smirnoff { 7059f7d47b0SAlexander V. Chernikov ipfw_xtable *xtbl; 7069f7d47b0SAlexander V. Chernikov struct dump_args *da; 7079f7d47b0SAlexander V. Chernikov struct table_config *tc; 7089f7d47b0SAlexander V. Chernikov struct table_algo *ta; 7093b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 7103b3a8eb9SGleb Smirnoff 7119f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 7129f7d47b0SAlexander V. Chernikov 7139f7d47b0SAlexander V. Chernikov xtbl = da->xtbl; 7149f7d47b0SAlexander V. Chernikov tc = da->tc; 7159f7d47b0SAlexander V. Chernikov ta = tc->ta; 7169f7d47b0SAlexander V. Chernikov 7173b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 7189f7d47b0SAlexander V. Chernikov if (xtbl->cnt == xtbl->size) 7193b3a8eb9SGleb Smirnoff return (1); 7209f7d47b0SAlexander V. Chernikov xent = &xtbl->xent[xtbl->cnt]; 7213b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 7229f7d47b0SAlexander V. Chernikov xent->tbl = xtbl->tbl; 7239f7d47b0SAlexander V. Chernikov xtbl->cnt++; 7249f7d47b0SAlexander V. Chernikov 7259f7d47b0SAlexander V. Chernikov return (ta->dump_xentry(tc->astate, da->ti, e, xent)); 7269f7d47b0SAlexander V. Chernikov } 7279f7d47b0SAlexander V. Chernikov 7289f7d47b0SAlexander V. Chernikov 7299f7d47b0SAlexander V. Chernikov int 7309f7d47b0SAlexander V. Chernikov ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_xtable *xtbl) 7319f7d47b0SAlexander V. Chernikov { 7329f7d47b0SAlexander V. Chernikov struct table_config *tc; 7339f7d47b0SAlexander V. Chernikov struct table_algo *ta; 7349f7d47b0SAlexander V. Chernikov struct dump_args da; 7359f7d47b0SAlexander V. Chernikov 7369f7d47b0SAlexander V. Chernikov xtbl->cnt = 0; 7379f7d47b0SAlexander V. Chernikov 7389f7d47b0SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 7399f7d47b0SAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 7409f7d47b0SAlexander V. Chernikov 7419f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 7429f7d47b0SAlexander V. Chernikov da.tc = tc; 7439f7d47b0SAlexander V. Chernikov da.xtbl = xtbl; 7449f7d47b0SAlexander V. Chernikov xtbl->type = tc->no.type; 7459f7d47b0SAlexander V. Chernikov ta = tc->ta; 7469f7d47b0SAlexander V. Chernikov 7479f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 7489f7d47b0SAlexander V. Chernikov 7493b3a8eb9SGleb Smirnoff return (0); 7503b3a8eb9SGleb Smirnoff } 7513b3a8eb9SGleb Smirnoff 7529f7d47b0SAlexander V. Chernikov /* 7539f7d47b0SAlexander V. Chernikov * Table algorithms 7549f7d47b0SAlexander V. Chernikov */ 7553b3a8eb9SGleb Smirnoff 7569f7d47b0SAlexander V. Chernikov /* 7579f7d47b0SAlexander V. Chernikov * Finds algoritm by index or table type 7589f7d47b0SAlexander V. Chernikov */ 7599f7d47b0SAlexander V. Chernikov static struct table_algo * 7609f7d47b0SAlexander V. Chernikov find_table_algo(struct tables_config *tcfg, struct tid_info *ti) 7619f7d47b0SAlexander V. Chernikov { 7629f7d47b0SAlexander V. Chernikov 7639f7d47b0SAlexander V. Chernikov /* Search by index */ 7649f7d47b0SAlexander V. Chernikov if (ti->atype != 0) { 7659f7d47b0SAlexander V. Chernikov if (ti->atype > tcfg->algo_count) 7669f7d47b0SAlexander V. Chernikov return (NULL); 7679f7d47b0SAlexander V. Chernikov return (tcfg->algo[ti->atype]); 7689f7d47b0SAlexander V. Chernikov } 7699f7d47b0SAlexander V. Chernikov 7709f7d47b0SAlexander V. Chernikov /* Search by type */ 7719f7d47b0SAlexander V. Chernikov switch (ti->type) { 7723b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 7739f7d47b0SAlexander V. Chernikov return (&radix_cidr); 7743b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 7759f7d47b0SAlexander V. Chernikov return (&radix_iface); 7763b3a8eb9SGleb Smirnoff } 7773b3a8eb9SGleb Smirnoff 7789f7d47b0SAlexander V. Chernikov return (NULL); 7793b3a8eb9SGleb Smirnoff } 7803b3a8eb9SGleb Smirnoff 7819f7d47b0SAlexander V. Chernikov void 7829f7d47b0SAlexander V. Chernikov ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta) 7833b3a8eb9SGleb Smirnoff { 7849f7d47b0SAlexander V. Chernikov struct tables_config *tcfg; 7853b3a8eb9SGleb Smirnoff 7869f7d47b0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 787b074b7bbSAlexander V. Chernikov 7889f7d47b0SAlexander V. Chernikov KASSERT(tcfg->algo_count < 255, ("Increase algo array size")); 7899f7d47b0SAlexander V. Chernikov 7909f7d47b0SAlexander V. Chernikov tcfg->algo[++tcfg->algo_count] = ta; 7919f7d47b0SAlexander V. Chernikov ta->idx = tcfg->algo_count; 7923b3a8eb9SGleb Smirnoff } 7933b3a8eb9SGleb Smirnoff 7949f7d47b0SAlexander V. Chernikov 795b074b7bbSAlexander V. Chernikov /* 796b074b7bbSAlexander V. Chernikov * Tables rewriting code 797b074b7bbSAlexander V. Chernikov * 798b074b7bbSAlexander V. Chernikov */ 799b074b7bbSAlexander V. Chernikov 800b074b7bbSAlexander V. Chernikov /* 801b074b7bbSAlexander V. Chernikov * Determine table number and lookup type for @cmd. 802b074b7bbSAlexander V. Chernikov * Fill @tbl and @type with appropriate values. 803b074b7bbSAlexander V. Chernikov * Returns 0 for relevant opcodes, 1 otherwise. 804b074b7bbSAlexander V. Chernikov */ 805b074b7bbSAlexander V. Chernikov static int 806b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 807b074b7bbSAlexander V. Chernikov { 808b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 809b074b7bbSAlexander V. Chernikov int skip; 810b074b7bbSAlexander V. Chernikov uint16_t v; 811b074b7bbSAlexander V. Chernikov 812b074b7bbSAlexander V. Chernikov skip = 1; 813b074b7bbSAlexander V. Chernikov 814b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 815b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 816b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 817b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 818b074b7bbSAlexander V. Chernikov *puidx = cmd->arg1; 819b074b7bbSAlexander V. Chernikov /* Assume CIDR by default */ 820b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 821b074b7bbSAlexander V. Chernikov skip = 0; 822b074b7bbSAlexander V. Chernikov 823b074b7bbSAlexander V. Chernikov if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { 824b074b7bbSAlexander V. Chernikov /* 825b074b7bbSAlexander V. Chernikov * generic lookup. The key must be 826b074b7bbSAlexander V. Chernikov * in 32bit big-endian format. 827b074b7bbSAlexander V. Chernikov */ 828b074b7bbSAlexander V. Chernikov v = ((ipfw_insn_u32 *)cmd)->d[1]; 829b074b7bbSAlexander V. Chernikov switch (v) { 830b074b7bbSAlexander V. Chernikov case 0: 831b074b7bbSAlexander V. Chernikov case 1: 832b074b7bbSAlexander V. Chernikov /* IPv4 src/dst */ 833b074b7bbSAlexander V. Chernikov break; 834b074b7bbSAlexander V. Chernikov case 2: 835b074b7bbSAlexander V. Chernikov case 3: 836b074b7bbSAlexander V. Chernikov /* src/dst port */ 837b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 838b074b7bbSAlexander V. Chernikov break; 839b074b7bbSAlexander V. Chernikov case 4: 840b074b7bbSAlexander V. Chernikov /* uid/gid */ 841b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 842b074b7bbSAlexander V. Chernikov case 5: 843b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 844b074b7bbSAlexander V. Chernikov /* jid */ 845b074b7bbSAlexander V. Chernikov case 6: 846b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 847b074b7bbSAlexander V. Chernikov /* dscp */ 848b074b7bbSAlexander V. Chernikov break; 849b074b7bbSAlexander V. Chernikov } 850b074b7bbSAlexander V. Chernikov } 851b074b7bbSAlexander V. Chernikov break; 852b074b7bbSAlexander V. Chernikov case O_XMIT: 853b074b7bbSAlexander V. Chernikov case O_RECV: 854b074b7bbSAlexander V. Chernikov case O_VIA: 855b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 856b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 857b074b7bbSAlexander V. Chernikov if (cmdif->name[0] != '\1') 858b074b7bbSAlexander V. Chernikov break; 859b074b7bbSAlexander V. Chernikov 860b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 861b074b7bbSAlexander V. Chernikov *puidx = cmdif->p.glob; 862b074b7bbSAlexander V. Chernikov skip = 0; 863b074b7bbSAlexander V. Chernikov break; 864b074b7bbSAlexander V. Chernikov } 865b074b7bbSAlexander V. Chernikov 866b074b7bbSAlexander V. Chernikov return (skip); 867b074b7bbSAlexander V. Chernikov } 868b074b7bbSAlexander V. Chernikov 869b074b7bbSAlexander V. Chernikov /* 870b074b7bbSAlexander V. Chernikov * Sets new table value for given opcode. 871b074b7bbSAlexander V. Chernikov * Assume the same opcodes as classify_table_opcode() 872b074b7bbSAlexander V. Chernikov */ 873b074b7bbSAlexander V. Chernikov static void 874b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx) 875b074b7bbSAlexander V. Chernikov { 876b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 877b074b7bbSAlexander V. Chernikov 878b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 879b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 880b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 881b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 882b074b7bbSAlexander V. Chernikov cmd->arg1 = idx; 883b074b7bbSAlexander V. Chernikov break; 884b074b7bbSAlexander V. Chernikov case O_XMIT: 885b074b7bbSAlexander V. Chernikov case O_RECV: 886b074b7bbSAlexander V. Chernikov case O_VIA: 887b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 888b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 889b074b7bbSAlexander V. Chernikov cmdif->p.glob = idx; 890b074b7bbSAlexander V. Chernikov break; 891b074b7bbSAlexander V. Chernikov } 892b074b7bbSAlexander V. Chernikov } 893b074b7bbSAlexander V. Chernikov 894b074b7bbSAlexander V. Chernikov static char * 895b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx) 896b074b7bbSAlexander V. Chernikov { 8979f7d47b0SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 898b074b7bbSAlexander V. Chernikov uintptr_t pa, pe; 899b074b7bbSAlexander V. Chernikov int l; 900b074b7bbSAlexander V. Chernikov 901b074b7bbSAlexander V. Chernikov pa = (uintptr_t)tlvs; 902b074b7bbSAlexander V. Chernikov pe = pa + len; 903b074b7bbSAlexander V. Chernikov l = 0; 904b074b7bbSAlexander V. Chernikov for (; pa < pe; pa += l) { 9059f7d47b0SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)pa; 906b074b7bbSAlexander V. Chernikov l = ntlv->head.length; 907b074b7bbSAlexander V. Chernikov if (ntlv->head.type != IPFW_TLV_NAME) 908b074b7bbSAlexander V. Chernikov continue; 909b074b7bbSAlexander V. Chernikov if (ntlv->idx != uidx) 910b074b7bbSAlexander V. Chernikov continue; 911b074b7bbSAlexander V. Chernikov 912b074b7bbSAlexander V. Chernikov return (ntlv->name); 913b074b7bbSAlexander V. Chernikov } 914b074b7bbSAlexander V. Chernikov 915b074b7bbSAlexander V. Chernikov return (NULL); 916b074b7bbSAlexander V. Chernikov } 917b074b7bbSAlexander V. Chernikov 918b074b7bbSAlexander V. Chernikov static struct table_config * 919b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti) 920b074b7bbSAlexander V. Chernikov { 921b074b7bbSAlexander V. Chernikov char *name, bname[16]; 922b074b7bbSAlexander V. Chernikov struct named_object *no; 923b074b7bbSAlexander V. Chernikov 924b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 925b074b7bbSAlexander V. Chernikov name = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 926b074b7bbSAlexander V. Chernikov if (name == NULL) 927b074b7bbSAlexander V. Chernikov return (NULL); 928b074b7bbSAlexander V. Chernikov } else { 929b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 930b074b7bbSAlexander V. Chernikov name = bname; 931b074b7bbSAlexander V. Chernikov } 932b074b7bbSAlexander V. Chernikov 933b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_name(ni, ti->set, name); 934b074b7bbSAlexander V. Chernikov 935b074b7bbSAlexander V. Chernikov return ((struct table_config *)no); 936b074b7bbSAlexander V. Chernikov } 937b074b7bbSAlexander V. Chernikov 938b074b7bbSAlexander V. Chernikov static struct table_config * 9399f7d47b0SAlexander V. Chernikov alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti, 9409f7d47b0SAlexander V. Chernikov struct table_algo *ta) 941b074b7bbSAlexander V. Chernikov { 942b074b7bbSAlexander V. Chernikov char *name, bname[16]; 943b074b7bbSAlexander V. Chernikov struct table_config *tc; 944b074b7bbSAlexander V. Chernikov int error; 945b074b7bbSAlexander V. Chernikov 946b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 947b074b7bbSAlexander V. Chernikov name = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 948b074b7bbSAlexander V. Chernikov if (name == NULL) 949b074b7bbSAlexander V. Chernikov return (NULL); 950b074b7bbSAlexander V. Chernikov } else { 951b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 952b074b7bbSAlexander V. Chernikov name = bname; 953b074b7bbSAlexander V. Chernikov } 954b074b7bbSAlexander V. Chernikov 955b074b7bbSAlexander V. Chernikov tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO); 956b074b7bbSAlexander V. Chernikov tc->no.name = tc->tablename; 957b074b7bbSAlexander V. Chernikov tc->no.type = ti->type; 958b074b7bbSAlexander V. Chernikov tc->no.set = ti->set; 9599f7d47b0SAlexander V. Chernikov tc->ta = ta; 960b074b7bbSAlexander V. Chernikov strlcpy(tc->tablename, name, sizeof(tc->tablename)); 961b074b7bbSAlexander V. Chernikov 962b074b7bbSAlexander V. Chernikov if (ti->tlvs == NULL) { 963b074b7bbSAlexander V. Chernikov tc->no.compat = 1; 964b074b7bbSAlexander V. Chernikov tc->no.uidx = ti->uidx; 965b074b7bbSAlexander V. Chernikov } 966b074b7bbSAlexander V. Chernikov 967b074b7bbSAlexander V. Chernikov /* Preallocate data structures for new tables */ 9689f7d47b0SAlexander V. Chernikov error = ta->init(&tc->astate, &tc->ti); 969b074b7bbSAlexander V. Chernikov if (error != 0) { 970b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 971b074b7bbSAlexander V. Chernikov return (NULL); 972b074b7bbSAlexander V. Chernikov } 973b074b7bbSAlexander V. Chernikov 974b074b7bbSAlexander V. Chernikov return (tc); 975b074b7bbSAlexander V. Chernikov } 976b074b7bbSAlexander V. Chernikov 977b074b7bbSAlexander V. Chernikov static void 978b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc) 979b074b7bbSAlexander V. Chernikov { 980b074b7bbSAlexander V. Chernikov 981b074b7bbSAlexander V. Chernikov if (tc->linked == 0) 9829f7d47b0SAlexander V. Chernikov tc->ta->destroy(&tc->astate, &tc->ti); 983b074b7bbSAlexander V. Chernikov 984b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 985b074b7bbSAlexander V. Chernikov } 986b074b7bbSAlexander V. Chernikov 987b074b7bbSAlexander V. Chernikov /* 988b074b7bbSAlexander V. Chernikov * Links @tc to @chain table named instance. 989b074b7bbSAlexander V. Chernikov * Sets appropriate type/states in @chain table info. 990b074b7bbSAlexander V. Chernikov */ 991b074b7bbSAlexander V. Chernikov static void 9929f7d47b0SAlexander V. Chernikov link_table(struct ip_fw_chain *ch, struct table_config *tc) 993b074b7bbSAlexander V. Chernikov { 994b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 9959f7d47b0SAlexander V. Chernikov struct table_info *ti; 996b074b7bbSAlexander V. Chernikov uint16_t kidx; 997b074b7bbSAlexander V. Chernikov 9989f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 9999f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1000b074b7bbSAlexander V. Chernikov 10019f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1002b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1003b074b7bbSAlexander V. Chernikov 1004b074b7bbSAlexander V. Chernikov ipfw_objhash_add(ni, &tc->no); 10059f7d47b0SAlexander V. Chernikov 10069f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 10079f7d47b0SAlexander V. Chernikov *ti = tc->ti; 1008b074b7bbSAlexander V. Chernikov 1009b074b7bbSAlexander V. Chernikov tc->linked = 1; 1010b074b7bbSAlexander V. Chernikov } 1011b074b7bbSAlexander V. Chernikov 1012b074b7bbSAlexander V. Chernikov /* 1013b074b7bbSAlexander V. Chernikov * Unlinks @tc from @chain table named instance. 1014b074b7bbSAlexander V. Chernikov * Zeroes states in @chain and stores them in @tc. 1015b074b7bbSAlexander V. Chernikov */ 1016b074b7bbSAlexander V. Chernikov static void 10179f7d47b0SAlexander V. Chernikov unlink_table(struct ip_fw_chain *ch, struct table_config *tc) 1018b074b7bbSAlexander V. Chernikov { 1019b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 10209f7d47b0SAlexander V. Chernikov struct table_info *ti; 1021b074b7bbSAlexander V. Chernikov uint16_t kidx; 1022b074b7bbSAlexander V. Chernikov 10239f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 10249f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1025b074b7bbSAlexander V. Chernikov 10269f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1027b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1028b074b7bbSAlexander V. Chernikov 10299f7d47b0SAlexander V. Chernikov /* Clear state. @ti copy is already saved inside @tc */ 1030b074b7bbSAlexander V. Chernikov ipfw_objhash_del(ni, &tc->no); 10319f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 10329f7d47b0SAlexander V. Chernikov memset(ti, 0, sizeof(struct table_info)); 1033b074b7bbSAlexander V. Chernikov tc->linked = 0; 1034b074b7bbSAlexander V. Chernikov } 1035b074b7bbSAlexander V. Chernikov 1036b074b7bbSAlexander V. Chernikov /* 1037b074b7bbSAlexander V. Chernikov * Finds named object by @uidx number. 1038b074b7bbSAlexander V. Chernikov * Refs found object, allocate new index for non-existing object. 1039b074b7bbSAlexander V. Chernikov * Fills in @pidx with userland/kernel indexes. 1040b074b7bbSAlexander V. Chernikov * 1041b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1042b074b7bbSAlexander V. Chernikov */ 1043b074b7bbSAlexander V. Chernikov static int 1044b074b7bbSAlexander V. Chernikov bind_table(struct namedobj_instance *ni, struct rule_check_info *ci, 1045b074b7bbSAlexander V. Chernikov struct obj_idx *pidx, struct tid_info *ti) 1046b074b7bbSAlexander V. Chernikov { 1047b074b7bbSAlexander V. Chernikov struct table_config *tc; 1048b074b7bbSAlexander V. Chernikov 1049b074b7bbSAlexander V. Chernikov pidx->uidx = ti->uidx; 1050b074b7bbSAlexander V. Chernikov pidx->type = ti->type; 1051b074b7bbSAlexander V. Chernikov 10529f7d47b0SAlexander V. Chernikov tc = find_table(ni, ti); 10539f7d47b0SAlexander V. Chernikov 1054b074b7bbSAlexander V. Chernikov if (tc == NULL) { 1055b074b7bbSAlexander V. Chernikov /* Try to acquire refcount */ 1056b074b7bbSAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, ti->set, &pidx->kidx) != 0) { 1057b074b7bbSAlexander V. Chernikov printf("Unable to allocate table index in set %u." 1058b074b7bbSAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 1059b074b7bbSAlexander V. Chernikov ti->set); 1060b074b7bbSAlexander V. Chernikov return (EBUSY); 1061b074b7bbSAlexander V. Chernikov } 1062b074b7bbSAlexander V. Chernikov 1063b074b7bbSAlexander V. Chernikov pidx->new = 1; 1064b074b7bbSAlexander V. Chernikov ci->new_tables++; 1065b074b7bbSAlexander V. Chernikov 1066b074b7bbSAlexander V. Chernikov return (0); 1067b074b7bbSAlexander V. Chernikov } 1068b074b7bbSAlexander V. Chernikov 1069b074b7bbSAlexander V. Chernikov /* Check if table type if valid first */ 1070b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) 1071b074b7bbSAlexander V. Chernikov return (EINVAL); 1072b074b7bbSAlexander V. Chernikov 1073b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 1074b074b7bbSAlexander V. Chernikov 1075b074b7bbSAlexander V. Chernikov pidx->kidx = tc->no.kidx; 1076b074b7bbSAlexander V. Chernikov 1077b074b7bbSAlexander V. Chernikov return (0); 1078b074b7bbSAlexander V. Chernikov } 1079b074b7bbSAlexander V. Chernikov 1080b074b7bbSAlexander V. Chernikov /* 1081b074b7bbSAlexander V. Chernikov * Compatibility function for old ipfw(8) binaries. 1082b074b7bbSAlexander V. Chernikov * Rewrites table kernel indices with userland ones. 1083b074b7bbSAlexander V. Chernikov * Works for \d+ talbes only (e.g. for tables, converted 1084b074b7bbSAlexander V. Chernikov * from old numbered system calls). 1085b074b7bbSAlexander V. Chernikov * 1086b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1087b074b7bbSAlexander V. Chernikov * Raises error on any other tables. 1088b074b7bbSAlexander V. Chernikov */ 1089b074b7bbSAlexander V. Chernikov int 1090b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule) 1091b074b7bbSAlexander V. Chernikov { 1092b074b7bbSAlexander V. Chernikov int cmdlen, l; 1093b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1094b074b7bbSAlexander V. Chernikov uint32_t set; 1095b074b7bbSAlexander V. Chernikov uint16_t kidx; 1096b074b7bbSAlexander V. Chernikov uint8_t type; 1097b074b7bbSAlexander V. Chernikov struct named_object *no; 1098b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1099b074b7bbSAlexander V. Chernikov 1100b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1101b074b7bbSAlexander V. Chernikov 1102b074b7bbSAlexander V. Chernikov set = TABLE_SET(rule->set); 1103b074b7bbSAlexander V. Chernikov 1104b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1105b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1106b074b7bbSAlexander V. Chernikov cmdlen = 0; 1107b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1108b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1109b074b7bbSAlexander V. Chernikov 1110b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1111b074b7bbSAlexander V. Chernikov continue; 1112b074b7bbSAlexander V. Chernikov 1113b074b7bbSAlexander V. Chernikov if ((no = ipfw_objhash_lookup_idx(ni, set, kidx)) == NULL) 1114b074b7bbSAlexander V. Chernikov return (1); 1115b074b7bbSAlexander V. Chernikov 1116b074b7bbSAlexander V. Chernikov if (no->compat == 0) 1117b074b7bbSAlexander V. Chernikov return (2); 1118b074b7bbSAlexander V. Chernikov 1119b074b7bbSAlexander V. Chernikov update_table_opcode(cmd, no->uidx); 1120b074b7bbSAlexander V. Chernikov } 1121b074b7bbSAlexander V. Chernikov 1122b074b7bbSAlexander V. Chernikov return (0); 1123b074b7bbSAlexander V. Chernikov } 1124b074b7bbSAlexander V. Chernikov 1125b074b7bbSAlexander V. Chernikov 1126b074b7bbSAlexander V. Chernikov /* 1127b074b7bbSAlexander V. Chernikov * Checks is opcode is referencing table of appropriate type. 1128b074b7bbSAlexander V. Chernikov * Adds reference count for found table if true. 1129b074b7bbSAlexander V. Chernikov * Rewrites user-supplied opcode values with kernel ones. 1130b074b7bbSAlexander V. Chernikov * 1131b074b7bbSAlexander V. Chernikov * Returns 0 on success and appropriate error code otherwise. 1132b074b7bbSAlexander V. Chernikov */ 1133b074b7bbSAlexander V. Chernikov int 1134b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, 1135b074b7bbSAlexander V. Chernikov struct rule_check_info *ci) 1136b074b7bbSAlexander V. Chernikov { 1137b074b7bbSAlexander V. Chernikov int cmdlen, error, ftype, l; 1138b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1139b074b7bbSAlexander V. Chernikov uint16_t uidx; 1140b074b7bbSAlexander V. Chernikov uint8_t type; 1141b074b7bbSAlexander V. Chernikov struct table_config *tc; 11429f7d47b0SAlexander V. Chernikov struct table_algo *ta; 1143b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1144b074b7bbSAlexander V. Chernikov struct named_object *no, *no_n, *no_tmp; 1145b074b7bbSAlexander V. Chernikov struct obj_idx *pidx, *p, *oib; 1146b074b7bbSAlexander V. Chernikov struct namedobjects_head nh; 1147b074b7bbSAlexander V. Chernikov struct tid_info ti; 1148b074b7bbSAlexander V. Chernikov 1149b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1150b074b7bbSAlexander V. Chernikov 1151b074b7bbSAlexander V. Chernikov /* 1152b074b7bbSAlexander V. Chernikov * Prepare an array for storing opcode indices. 1153b074b7bbSAlexander V. Chernikov * Use stack allocation by default. 1154b074b7bbSAlexander V. Chernikov */ 1155b074b7bbSAlexander V. Chernikov if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 1156b074b7bbSAlexander V. Chernikov /* Stack */ 1157b074b7bbSAlexander V. Chernikov pidx = ci->obuf; 1158b074b7bbSAlexander V. Chernikov } else 1159b074b7bbSAlexander V. Chernikov pidx = malloc(ci->table_opcodes * sizeof(struct obj_idx), 1160b074b7bbSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1161b074b7bbSAlexander V. Chernikov 1162b074b7bbSAlexander V. Chernikov oib = pidx; 1163b074b7bbSAlexander V. Chernikov error = 0; 1164b074b7bbSAlexander V. Chernikov 1165b074b7bbSAlexander V. Chernikov type = 0; 1166b074b7bbSAlexander V. Chernikov ftype = 0; 1167b074b7bbSAlexander V. Chernikov 1168b074b7bbSAlexander V. Chernikov ci->tableset = TABLE_SET(ci->krule->set); 1169b074b7bbSAlexander V. Chernikov 1170b074b7bbSAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 1171b074b7bbSAlexander V. Chernikov ti.set = ci->tableset; 1172b074b7bbSAlexander V. Chernikov ti.tlvs = ci->tlvs; 1173b074b7bbSAlexander V. Chernikov ti.tlen = ci->tlen; 1174b074b7bbSAlexander V. Chernikov 1175b074b7bbSAlexander V. Chernikov /* 1176b074b7bbSAlexander V. Chernikov * Stage 1: reference existing tables and determine number 1177b074b7bbSAlexander V. Chernikov * of tables we need to allocate 1178b074b7bbSAlexander V. Chernikov */ 1179b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(chain); 1180b074b7bbSAlexander V. Chernikov 1181b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 1182b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 1183b074b7bbSAlexander V. Chernikov cmdlen = 0; 1184b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1185b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1186b074b7bbSAlexander V. Chernikov 1187b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &ti.uidx, &ti.type) != 0) 1188b074b7bbSAlexander V. Chernikov continue; 1189b074b7bbSAlexander V. Chernikov 1190b074b7bbSAlexander V. Chernikov /* 1191b074b7bbSAlexander V. Chernikov * Got table opcode with necessary info. 1192b074b7bbSAlexander V. Chernikov * Try to reference existing tables and allocate 1193b074b7bbSAlexander V. Chernikov * indices for non-existing one while holding write lock. 1194b074b7bbSAlexander V. Chernikov */ 11959f7d47b0SAlexander V. Chernikov if ((error = bind_table(ni, ci, pidx, &ti)) != 0) { 11969f7d47b0SAlexander V. Chernikov printf("error!\n"); 1197b074b7bbSAlexander V. Chernikov break; 11989f7d47b0SAlexander V. Chernikov } 1199b074b7bbSAlexander V. Chernikov 1200b074b7bbSAlexander V. Chernikov /* 1201b074b7bbSAlexander V. Chernikov * @pidx stores either existing ref'd table id or new one. 1202b074b7bbSAlexander V. Chernikov * Move to next index 1203b074b7bbSAlexander V. Chernikov */ 1204b074b7bbSAlexander V. Chernikov 1205b074b7bbSAlexander V. Chernikov pidx++; 1206b074b7bbSAlexander V. Chernikov } 1207b074b7bbSAlexander V. Chernikov 1208b074b7bbSAlexander V. Chernikov if (error != 0) { 1209b074b7bbSAlexander V. Chernikov /* Unref everything we have already done */ 1210b074b7bbSAlexander V. Chernikov for (p = oib; p < pidx; p++) { 1211b074b7bbSAlexander V. Chernikov if (p->new != 0) { 1212b074b7bbSAlexander V. Chernikov ipfw_objhash_free_idx(ni, ci->tableset,p->kidx); 1213b074b7bbSAlexander V. Chernikov continue; 1214b074b7bbSAlexander V. Chernikov } 1215b074b7bbSAlexander V. Chernikov 1216b074b7bbSAlexander V. Chernikov /* Find & unref by existing idx */ 1217b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_idx(ni, ci->tableset, p->kidx); 1218b074b7bbSAlexander V. Chernikov KASSERT(no!=NULL, ("Ref'd table %d disappeared", 1219b074b7bbSAlexander V. Chernikov p->kidx)); 1220b074b7bbSAlexander V. Chernikov 1221b074b7bbSAlexander V. Chernikov no->refcnt--; 1222b074b7bbSAlexander V. Chernikov } 1223b074b7bbSAlexander V. Chernikov 1224b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1225b074b7bbSAlexander V. Chernikov 1226b074b7bbSAlexander V. Chernikov if (oib != ci->obuf) 1227b074b7bbSAlexander V. Chernikov free(oib, M_IPFW); 1228b074b7bbSAlexander V. Chernikov 1229b074b7bbSAlexander V. Chernikov return (error); 1230b074b7bbSAlexander V. Chernikov } 1231b074b7bbSAlexander V. Chernikov 1232b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1233b074b7bbSAlexander V. Chernikov 1234b074b7bbSAlexander V. Chernikov /* 1235b074b7bbSAlexander V. Chernikov * Stage 2: allocate table configs for every non-existent table 1236b074b7bbSAlexander V. Chernikov */ 1237b074b7bbSAlexander V. Chernikov 1238b074b7bbSAlexander V. Chernikov /* Prepare queue to store configs */ 1239b074b7bbSAlexander V. Chernikov TAILQ_INIT(&nh); 12409f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 1241b074b7bbSAlexander V. Chernikov for (p = oib; p < pidx; p++) { 1242b074b7bbSAlexander V. Chernikov if (p->new == 0) 1243b074b7bbSAlexander V. Chernikov continue; 1244b074b7bbSAlexander V. Chernikov 1245b074b7bbSAlexander V. Chernikov /* TODO: get name from TLV */ 1246b074b7bbSAlexander V. Chernikov ti.uidx = p->uidx; 1247b074b7bbSAlexander V. Chernikov ti.type = p->type; 12489f7d47b0SAlexander V. Chernikov ti.atype = 0; 1249b074b7bbSAlexander V. Chernikov 12509f7d47b0SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti); 12519f7d47b0SAlexander V. Chernikov if (ta == NULL) { 12529f7d47b0SAlexander V. Chernikov error = ENOTSUP; 12539f7d47b0SAlexander V. Chernikov goto free; 12549f7d47b0SAlexander V. Chernikov } 12559f7d47b0SAlexander V. Chernikov tc = alloc_table_config(ni, &ti, ta); 1256b074b7bbSAlexander V. Chernikov 1257b074b7bbSAlexander V. Chernikov if (tc == NULL) { 1258b074b7bbSAlexander V. Chernikov error = ENOMEM; 1259b074b7bbSAlexander V. Chernikov goto free; 1260b074b7bbSAlexander V. Chernikov } 1261b074b7bbSAlexander V. Chernikov 1262b074b7bbSAlexander V. Chernikov tc->no.kidx = p->kidx; 1263b074b7bbSAlexander V. Chernikov tc->no.refcnt = 1; 1264b074b7bbSAlexander V. Chernikov 1265b074b7bbSAlexander V. Chernikov /* Add to list */ 1266b074b7bbSAlexander V. Chernikov TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next); 1267b074b7bbSAlexander V. Chernikov } 1268b074b7bbSAlexander V. Chernikov 1269b074b7bbSAlexander V. Chernikov /* 1270b074b7bbSAlexander V. Chernikov * Stage 2.1: Check if we're going to create 2 tables 1271b074b7bbSAlexander V. Chernikov * with the same name, but different table types. 1272b074b7bbSAlexander V. Chernikov */ 1273b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no, &nh, nn_next) { 1274b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no_tmp, &nh, nn_next) { 1275b074b7bbSAlexander V. Chernikov if (strcmp(no->name, no_tmp->name) != 0) 1276b074b7bbSAlexander V. Chernikov continue; 1277b074b7bbSAlexander V. Chernikov if (no->type != no_tmp->type) { 1278b074b7bbSAlexander V. Chernikov error = EINVAL; 1279b074b7bbSAlexander V. Chernikov goto free; 1280b074b7bbSAlexander V. Chernikov } 1281b074b7bbSAlexander V. Chernikov } 1282b074b7bbSAlexander V. Chernikov } 12839f7d47b0SAlexander V. Chernikov } 1284b074b7bbSAlexander V. Chernikov 12859f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 12869f7d47b0SAlexander V. Chernikov 12879f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 1288b074b7bbSAlexander V. Chernikov /* 1289b074b7bbSAlexander V. Chernikov * Stage 3: link & reference new table configs 1290b074b7bbSAlexander V. Chernikov */ 1291b074b7bbSAlexander V. Chernikov 1292b074b7bbSAlexander V. Chernikov 1293b074b7bbSAlexander V. Chernikov /* 1294b074b7bbSAlexander V. Chernikov * Step 3.1: Check if some tables we need to create have been 1295b074b7bbSAlexander V. Chernikov * already created with different table type. 1296b074b7bbSAlexander V. Chernikov */ 1297b074b7bbSAlexander V. Chernikov 1298b074b7bbSAlexander V. Chernikov error = 0; 1299b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1300b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1301b074b7bbSAlexander V. Chernikov if (no_n == NULL) 1302b074b7bbSAlexander V. Chernikov continue; 1303b074b7bbSAlexander V. Chernikov 1304b074b7bbSAlexander V. Chernikov if (no_n->type != no->type) { 1305b074b7bbSAlexander V. Chernikov error = EINVAL; 1306b074b7bbSAlexander V. Chernikov break; 1307b074b7bbSAlexander V. Chernikov } 1308b074b7bbSAlexander V. Chernikov 1309b074b7bbSAlexander V. Chernikov } 1310b074b7bbSAlexander V. Chernikov 1311b074b7bbSAlexander V. Chernikov if (error != 0) { 1312b074b7bbSAlexander V. Chernikov /* 1313b074b7bbSAlexander V. Chernikov * Someone has allocated table with different table type. 1314b074b7bbSAlexander V. Chernikov * We have to rollback everything. 1315b074b7bbSAlexander V. Chernikov */ 1316b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1317b074b7bbSAlexander V. Chernikov 1318b074b7bbSAlexander V. Chernikov goto free; 1319b074b7bbSAlexander V. Chernikov } 1320b074b7bbSAlexander V. Chernikov 1321b074b7bbSAlexander V. Chernikov 1322b074b7bbSAlexander V. Chernikov /* 13239f7d47b0SAlexander V. Chernikov * Attach new tables. 13249f7d47b0SAlexander V. Chernikov * We need to set table pointers for each new table, 1325b074b7bbSAlexander V. Chernikov * so we have to acquire main WLOCK. 1326b074b7bbSAlexander V. Chernikov */ 1327b074b7bbSAlexander V. Chernikov IPFW_WLOCK(chain); 1328b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1329b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1330b074b7bbSAlexander V. Chernikov if (no_n != NULL) { 1331b074b7bbSAlexander V. Chernikov /* Increase refcount for existing table */ 1332b074b7bbSAlexander V. Chernikov no_n->refcnt++; 1333b074b7bbSAlexander V. Chernikov /* Keep oib array in sync: update kindx */ 1334b074b7bbSAlexander V. Chernikov for (p = oib; p < pidx; p++) { 1335b074b7bbSAlexander V. Chernikov if (p->kidx == no->kidx) { 1336b074b7bbSAlexander V. Chernikov p->kidx = no_n->kidx; 1337b074b7bbSAlexander V. Chernikov break; 1338b074b7bbSAlexander V. Chernikov } 1339b074b7bbSAlexander V. Chernikov } 1340b074b7bbSAlexander V. Chernikov 1341b074b7bbSAlexander V. Chernikov continue; 1342b074b7bbSAlexander V. Chernikov } 1343b074b7bbSAlexander V. Chernikov 1344b074b7bbSAlexander V. Chernikov /* New table. Attach to runtime hash */ 1345b074b7bbSAlexander V. Chernikov TAILQ_REMOVE(&nh, no, nn_next); 1346b074b7bbSAlexander V. Chernikov 1347b074b7bbSAlexander V. Chernikov link_table(chain, (struct table_config *)no); 1348b074b7bbSAlexander V. Chernikov } 1349b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(chain); 13509f7d47b0SAlexander V. Chernikov } 1351b074b7bbSAlexander V. Chernikov 1352b074b7bbSAlexander V. Chernikov /* Perform rule rewrite */ 1353b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 1354b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 1355b074b7bbSAlexander V. Chernikov cmdlen = 0; 1356b074b7bbSAlexander V. Chernikov pidx = oib; 1357b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1358b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1359b074b7bbSAlexander V. Chernikov 1360b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &uidx, &type) != 0) 1361b074b7bbSAlexander V. Chernikov continue; 1362b074b7bbSAlexander V. Chernikov update_table_opcode(cmd, pidx->kidx); 1363b074b7bbSAlexander V. Chernikov pidx++; 1364b074b7bbSAlexander V. Chernikov } 1365b074b7bbSAlexander V. Chernikov 1366b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1367b074b7bbSAlexander V. Chernikov 1368b074b7bbSAlexander V. Chernikov error = 0; 1369b074b7bbSAlexander V. Chernikov 1370b074b7bbSAlexander V. Chernikov /* 1371b074b7bbSAlexander V. Chernikov * Stage 4: free resources 1372b074b7bbSAlexander V. Chernikov */ 1373b074b7bbSAlexander V. Chernikov free: 1374b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) 1375b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 1376b074b7bbSAlexander V. Chernikov 1377b074b7bbSAlexander V. Chernikov if (oib != ci->obuf) 1378b074b7bbSAlexander V. Chernikov free(oib, M_IPFW); 1379b074b7bbSAlexander V. Chernikov 1380b074b7bbSAlexander V. Chernikov return (error); 1381b074b7bbSAlexander V. Chernikov } 1382b074b7bbSAlexander V. Chernikov 1383b074b7bbSAlexander V. Chernikov /* 1384b074b7bbSAlexander V. Chernikov * Remove references from every table used in @rule. 1385b074b7bbSAlexander V. Chernikov */ 1386b074b7bbSAlexander V. Chernikov void 1387b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule) 1388b074b7bbSAlexander V. Chernikov { 1389b074b7bbSAlexander V. Chernikov int cmdlen, l; 1390b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1391b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1392b074b7bbSAlexander V. Chernikov struct named_object *no; 1393b074b7bbSAlexander V. Chernikov uint32_t set; 1394b074b7bbSAlexander V. Chernikov uint16_t kidx; 1395b074b7bbSAlexander V. Chernikov uint8_t type; 1396b074b7bbSAlexander V. Chernikov 1397b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1398b074b7bbSAlexander V. Chernikov 1399b074b7bbSAlexander V. Chernikov set = TABLE_SET(rule->set); 1400b074b7bbSAlexander V. Chernikov 1401b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1402b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1403b074b7bbSAlexander V. Chernikov cmdlen = 0; 1404b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1405b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1406b074b7bbSAlexander V. Chernikov 1407b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1408b074b7bbSAlexander V. Chernikov continue; 1409b074b7bbSAlexander V. Chernikov 1410b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_idx(ni, set, kidx); 1411b074b7bbSAlexander V. Chernikov 1412b074b7bbSAlexander V. Chernikov KASSERT(no != NULL, ("table id %d not found", kidx)); 1413b074b7bbSAlexander V. Chernikov KASSERT(no->type == type, ("wrong type %d (%d) for table id %d", 1414b074b7bbSAlexander V. Chernikov no->type, type, kidx)); 1415b074b7bbSAlexander V. Chernikov KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 1416b074b7bbSAlexander V. Chernikov kidx, no->refcnt)); 1417b074b7bbSAlexander V. Chernikov 1418b074b7bbSAlexander V. Chernikov no->refcnt--; 1419b074b7bbSAlexander V. Chernikov } 1420b074b7bbSAlexander V. Chernikov } 1421b074b7bbSAlexander V. Chernikov 1422b074b7bbSAlexander V. Chernikov 1423b074b7bbSAlexander V. Chernikov /* 1424b074b7bbSAlexander V. Chernikov * Removes table bindings for every rule in rule chain @head. 1425b074b7bbSAlexander V. Chernikov */ 1426b074b7bbSAlexander V. Chernikov void 1427b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head) 1428b074b7bbSAlexander V. Chernikov { 1429b074b7bbSAlexander V. Chernikov struct ip_fw *rule; 1430b074b7bbSAlexander V. Chernikov 1431b074b7bbSAlexander V. Chernikov while ((rule = head) != NULL) { 1432b074b7bbSAlexander V. Chernikov head = head->x_next; 1433b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(chain, rule); 1434b074b7bbSAlexander V. Chernikov } 1435b074b7bbSAlexander V. Chernikov } 1436b074b7bbSAlexander V. Chernikov 1437b074b7bbSAlexander V. Chernikov 14383b3a8eb9SGleb Smirnoff /* end of file */ 1439