13b3a8eb9SGleb Smirnoff /*- 23b3a8eb9SGleb Smirnoff * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. 33b3a8eb9SGleb Smirnoff * 43b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 53b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions 63b3a8eb9SGleb Smirnoff * are met: 73b3a8eb9SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 83b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 93b3a8eb9SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 103b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 113b3a8eb9SGleb Smirnoff * documentation and/or other materials provided with the distribution. 123b3a8eb9SGleb Smirnoff * 133b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 143b3a8eb9SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 153b3a8eb9SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 163b3a8eb9SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 173b3a8eb9SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 183b3a8eb9SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 193b3a8eb9SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 203b3a8eb9SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 213b3a8eb9SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 223b3a8eb9SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 233b3a8eb9SGleb Smirnoff * SUCH DAMAGE. 243b3a8eb9SGleb Smirnoff */ 253b3a8eb9SGleb Smirnoff 263b3a8eb9SGleb Smirnoff #include <sys/cdefs.h> 273b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$"); 283b3a8eb9SGleb Smirnoff 293b3a8eb9SGleb Smirnoff /* 30563b5ab1SAlexander V. Chernikov * Lookup table support for ipfw. 313b3a8eb9SGleb Smirnoff * 32ac35ff17SAlexander V. Chernikov * This file contains handlers for all generic tables' operations: 33563b5ab1SAlexander V. Chernikov * add/del/flush entries, list/dump tables etc.. 343b3a8eb9SGleb Smirnoff * 35563b5ab1SAlexander V. Chernikov * Table data modification is protected by both UH and runtimg lock 36563b5ab1SAlexander V. Chernikov * while reading configuration/data is protected by UH lock. 37563b5ab1SAlexander V. Chernikov * 38563b5ab1SAlexander V. Chernikov * Lookup algorithms for all table types are located in ip_fw_table_algo.c 393b3a8eb9SGleb Smirnoff */ 403b3a8eb9SGleb Smirnoff 413b3a8eb9SGleb Smirnoff #include "opt_ipfw.h" 423b3a8eb9SGleb Smirnoff 433b3a8eb9SGleb Smirnoff #include <sys/param.h> 443b3a8eb9SGleb Smirnoff #include <sys/systm.h> 453b3a8eb9SGleb Smirnoff #include <sys/malloc.h> 463b3a8eb9SGleb Smirnoff #include <sys/kernel.h> 473b3a8eb9SGleb Smirnoff #include <sys/lock.h> 483b3a8eb9SGleb Smirnoff #include <sys/rwlock.h> 493b3a8eb9SGleb Smirnoff #include <sys/socket.h> 50f1220db8SAlexander V. Chernikov #include <sys/socketvar.h> 513b3a8eb9SGleb Smirnoff #include <sys/queue.h> 523b3a8eb9SGleb Smirnoff #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 533b3a8eb9SGleb Smirnoff #include <net/route.h> 543b3a8eb9SGleb Smirnoff #include <net/vnet.h> 553b3a8eb9SGleb Smirnoff 563b3a8eb9SGleb Smirnoff #include <netinet/in.h> 573b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 583b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h> 593b3a8eb9SGleb Smirnoff 603b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h> 61ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 623b3a8eb9SGleb Smirnoff 633b3a8eb9SGleb Smirnoff 643b3a8eb9SGleb Smirnoff /* 65b074b7bbSAlexander V. Chernikov * Table has the following `type` concepts: 66b074b7bbSAlexander V. Chernikov * 679f7d47b0SAlexander V. Chernikov * `no.type` represents lookup key type (cidr, ifp, uid, etc..) 689f7d47b0SAlexander V. Chernikov * `ta->atype` represents exact lookup algorithm. 69b074b7bbSAlexander V. Chernikov * For example, we can use more efficient search schemes if we plan 70b074b7bbSAlexander V. Chernikov * to use some specific table for storing host-routes only. 719490a627SAlexander V. Chernikov * `ftype` (at the moment )is pure userland field helping to properly 729490a627SAlexander V. Chernikov * format value data e.g. "value is IPv4 nexthop" or "value is DSCP" 739490a627SAlexander V. Chernikov * or "value is port". 74b074b7bbSAlexander V. Chernikov * 75b074b7bbSAlexander V. Chernikov */ 76b074b7bbSAlexander V. Chernikov struct table_config { 77b074b7bbSAlexander V. Chernikov struct named_object no; 78ac35ff17SAlexander V. Chernikov uint8_t vtype; /* format table type */ 79b074b7bbSAlexander V. Chernikov uint8_t linked; /* 1 if already linked */ 809f7d47b0SAlexander V. Chernikov uint16_t spare0; 81b074b7bbSAlexander V. Chernikov uint32_t count; /* Number of records */ 82b074b7bbSAlexander V. Chernikov char tablename[64]; /* table name */ 839f7d47b0SAlexander V. Chernikov struct table_algo *ta; /* Callbacks for given algo */ 849f7d47b0SAlexander V. Chernikov void *astate; /* algorithm state */ 859f7d47b0SAlexander V. Chernikov struct table_info ti; /* data to put to table_info */ 86b074b7bbSAlexander V. Chernikov }; 87b074b7bbSAlexander V. Chernikov #define TABLE_SET(set) ((V_fw_tables_sets != 0) ? set : 0) 88b074b7bbSAlexander V. Chernikov 89b074b7bbSAlexander V. Chernikov struct tables_config { 90b074b7bbSAlexander V. Chernikov struct namedobj_instance *namehash; 919f7d47b0SAlexander V. Chernikov int algo_count; 929f7d47b0SAlexander V. Chernikov struct table_algo *algo[256]; 93b074b7bbSAlexander V. Chernikov }; 94b074b7bbSAlexander V. Chernikov 95b074b7bbSAlexander V. Chernikov static struct table_config *find_table(struct namedobj_instance *ni, 96b074b7bbSAlexander V. Chernikov struct tid_info *ti); 97b074b7bbSAlexander V. Chernikov static struct table_config *alloc_table_config(struct namedobj_instance *ni, 989490a627SAlexander V. Chernikov struct tid_info *ti, struct table_algo *ta, char *adata); 99b074b7bbSAlexander V. Chernikov static void free_table_config(struct namedobj_instance *ni, 100b074b7bbSAlexander V. Chernikov struct table_config *tc); 101b074b7bbSAlexander V. Chernikov static void link_table(struct ip_fw_chain *chain, struct table_config *tc); 102b074b7bbSAlexander V. Chernikov static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc); 103b074b7bbSAlexander V. Chernikov static void free_table_state(void **state, void **xstate, uint8_t type); 1042d99a349SAlexander V. Chernikov static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 1052d99a349SAlexander V. Chernikov struct sockopt_data *sd); 106ac35ff17SAlexander V. Chernikov static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 107ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i); 10881d3153dSAlexander V. Chernikov static int dump_table_tentry(void *e, void *arg); 109f1220db8SAlexander V. Chernikov static int dump_table_xentry(void *e, void *arg); 110b074b7bbSAlexander V. Chernikov 1112d99a349SAlexander V. Chernikov static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd); 1122d99a349SAlexander V. Chernikov static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd); 113ac35ff17SAlexander V. Chernikov static int ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 114ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 115ac35ff17SAlexander V. Chernikov static int ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 116ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 117ac35ff17SAlexander V. Chernikov 118ac35ff17SAlexander V. Chernikov static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti); 119d3a4f924SAlexander V. Chernikov 1209f7d47b0SAlexander V. Chernikov static struct table_algo *find_table_algo(struct tables_config *tableconf, 1219490a627SAlexander V. Chernikov struct tid_info *ti, char *name); 122b074b7bbSAlexander V. Chernikov 123b074b7bbSAlexander V. Chernikov #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) 124b074b7bbSAlexander V. Chernikov #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) 1259f7d47b0SAlexander V. Chernikov #define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) 126b074b7bbSAlexander V. Chernikov 127b074b7bbSAlexander V. Chernikov 1283b3a8eb9SGleb Smirnoff 1293b3a8eb9SGleb Smirnoff int 1301832a7b3SAlexander V. Chernikov add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 131b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 1323b3a8eb9SGleb Smirnoff { 133b074b7bbSAlexander V. Chernikov struct table_config *tc, *tc_new; 1349f7d47b0SAlexander V. Chernikov struct table_algo *ta; 135b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 136b074b7bbSAlexander V. Chernikov uint16_t kidx; 1379f7d47b0SAlexander V. Chernikov int error; 1389f7d47b0SAlexander V. Chernikov char ta_buf[128]; 1393b3a8eb9SGleb Smirnoff 1409f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1419f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1429f7d47b0SAlexander V. Chernikov 1439f7d47b0SAlexander V. Chernikov /* 1449f7d47b0SAlexander V. Chernikov * Find and reference existing table. 1459f7d47b0SAlexander V. Chernikov */ 1469f7d47b0SAlexander V. Chernikov ta = NULL; 1479f7d47b0SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1489f7d47b0SAlexander V. Chernikov /* check table type */ 1499f7d47b0SAlexander V. Chernikov if (tc->no.type != ti->type) { 1509f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1513b3a8eb9SGleb Smirnoff return (EINVAL); 1523b3a8eb9SGleb Smirnoff } 1533b3a8eb9SGleb Smirnoff 1549f7d47b0SAlexander V. Chernikov /* Reference and unlock */ 1559f7d47b0SAlexander V. Chernikov tc->no.refcnt++; 1569f7d47b0SAlexander V. Chernikov ta = tc->ta; 1579f7d47b0SAlexander V. Chernikov } 1589f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1593b3a8eb9SGleb Smirnoff 1609f7d47b0SAlexander V. Chernikov tc_new = NULL; 161ac35ff17SAlexander V. Chernikov if (tc == NULL) { 1629f7d47b0SAlexander V. Chernikov /* Table not found. We have to create new one */ 1639490a627SAlexander V. Chernikov if ((ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, NULL)) == NULL) 1649f7d47b0SAlexander V. Chernikov return (ENOTSUP); 1653b3a8eb9SGleb Smirnoff 1669490a627SAlexander V. Chernikov tc_new = alloc_table_config(ni, ti, ta, NULL); 1679f7d47b0SAlexander V. Chernikov if (tc_new == NULL) 1689f7d47b0SAlexander V. Chernikov return (ENOMEM); 1699f7d47b0SAlexander V. Chernikov } 1703b3a8eb9SGleb Smirnoff 1719f7d47b0SAlexander V. Chernikov /* Prepare record (allocate memory) */ 1729f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 1739f7d47b0SAlexander V. Chernikov error = ta->prepare_add(tei, &ta_buf); 1749f7d47b0SAlexander V. Chernikov if (error != 0) { 1759f7d47b0SAlexander V. Chernikov if (tc_new != NULL) 1769f7d47b0SAlexander V. Chernikov free_table_config(ni, tc_new); 1779f7d47b0SAlexander V. Chernikov return (error); 1783b3a8eb9SGleb Smirnoff } 1793b3a8eb9SGleb Smirnoff 180b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1813b3a8eb9SGleb Smirnoff 182b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1833b3a8eb9SGleb Smirnoff 1849f7d47b0SAlexander V. Chernikov if (tc == NULL) { 185ac35ff17SAlexander V. Chernikov /* Check if another table has been allocated by other thread */ 186b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1879f7d47b0SAlexander V. Chernikov 1889f7d47b0SAlexander V. Chernikov /* 1899f7d47b0SAlexander V. Chernikov * Check if algoritm is the same since we've 1909f7d47b0SAlexander V. Chernikov * already allocated state using @ta algoritm 1919f7d47b0SAlexander V. Chernikov * callbacks. 1929f7d47b0SAlexander V. Chernikov */ 1939f7d47b0SAlexander V. Chernikov if (tc->ta != ta) { 194b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 195ac35ff17SAlexander V. Chernikov error = EINVAL; 196ac35ff17SAlexander V. Chernikov goto done; 1973b3a8eb9SGleb Smirnoff } 1983b3a8eb9SGleb Smirnoff } else { 199ac35ff17SAlexander V. Chernikov /* Table still does not exists */ 200b074b7bbSAlexander V. Chernikov 201b074b7bbSAlexander V. Chernikov /* Allocate table index. */ 202ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) { 203b074b7bbSAlexander V. Chernikov /* Index full. */ 204b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 205ac35ff17SAlexander V. Chernikov printf("Unable to allocate index for table %s" 206ac35ff17SAlexander V. Chernikov "in set %u. Consider increasing " 207b074b7bbSAlexander V. Chernikov "net.inet.ip.fw.tables_max", 208ac35ff17SAlexander V. Chernikov tc_new->no.name, ti->set); 209ac35ff17SAlexander V. Chernikov error = EBUSY; 210ac35ff17SAlexander V. Chernikov goto done; 2113b3a8eb9SGleb Smirnoff } 212ac35ff17SAlexander V. Chernikov 213ac35ff17SAlexander V. Chernikov /* Set tc_new to zero not to free it afterwards. */ 214ac35ff17SAlexander V. Chernikov tc = tc_new; 215ac35ff17SAlexander V. Chernikov tc_new = NULL; 216b074b7bbSAlexander V. Chernikov /* Save kidx */ 217b074b7bbSAlexander V. Chernikov tc->no.kidx = kidx; 218b074b7bbSAlexander V. Chernikov } 219b074b7bbSAlexander V. Chernikov } else { 2209f7d47b0SAlexander V. Chernikov /* Drop reference we've used in first search */ 2219f7d47b0SAlexander V. Chernikov tc->no.refcnt--; 222b074b7bbSAlexander V. Chernikov } 223b074b7bbSAlexander V. Chernikov 224b074b7bbSAlexander V. Chernikov /* We've got valid table in @tc. Let's add data */ 2259f7d47b0SAlexander V. Chernikov kidx = tc->no.kidx; 2269f7d47b0SAlexander V. Chernikov ta = tc->ta; 2279f7d47b0SAlexander V. Chernikov 228b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 229b074b7bbSAlexander V. Chernikov 230ac35ff17SAlexander V. Chernikov if (tc->linked == 0) 231b074b7bbSAlexander V. Chernikov link_table(ch, tc); 232b074b7bbSAlexander V. Chernikov 2339f7d47b0SAlexander V. Chernikov error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); 2343b3a8eb9SGleb Smirnoff 2353b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2369f7d47b0SAlexander V. Chernikov 237ac35ff17SAlexander V. Chernikov /* Update number of records. */ 238ac35ff17SAlexander V. Chernikov if (error == 0 && (tei->flags & TEI_FLAGS_UPDATED) == 0) 2399f7d47b0SAlexander V. Chernikov tc->count++; 2409f7d47b0SAlexander V. Chernikov 241b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 242b074b7bbSAlexander V. Chernikov 243ac35ff17SAlexander V. Chernikov done: 244b074b7bbSAlexander V. Chernikov if (tc_new != NULL) 245ac35ff17SAlexander V. Chernikov free_table_config(ni, tc_new); 246ac35ff17SAlexander V. Chernikov /* Run cleaning callback anyway */ 2479f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 248b074b7bbSAlexander V. Chernikov 2499f7d47b0SAlexander V. Chernikov return (error); 2503b3a8eb9SGleb Smirnoff } 2513b3a8eb9SGleb Smirnoff 2523b3a8eb9SGleb Smirnoff int 2531832a7b3SAlexander V. Chernikov del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 254b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 2553b3a8eb9SGleb Smirnoff { 256b074b7bbSAlexander V. Chernikov struct table_config *tc; 2579f7d47b0SAlexander V. Chernikov struct table_algo *ta; 258b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 259b074b7bbSAlexander V. Chernikov uint16_t kidx; 2609f7d47b0SAlexander V. Chernikov int error; 2619f7d47b0SAlexander V. Chernikov char ta_buf[128]; 2623b3a8eb9SGleb Smirnoff 2639f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 264b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 265b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 2669f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2673b3a8eb9SGleb Smirnoff return (ESRCH); 2683b3a8eb9SGleb Smirnoff } 2693b3a8eb9SGleb Smirnoff 270b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 2719f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2723b3a8eb9SGleb Smirnoff return (EINVAL); 2733b3a8eb9SGleb Smirnoff } 2749f7d47b0SAlexander V. Chernikov 2759f7d47b0SAlexander V. Chernikov ta = tc->ta; 2769f7d47b0SAlexander V. Chernikov 2779f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 2789f7d47b0SAlexander V. Chernikov if ((error = ta->prepare_del(tei, &ta_buf)) != 0) { 2799f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2809f7d47b0SAlexander V. Chernikov return (error); 2819f7d47b0SAlexander V. Chernikov } 2829f7d47b0SAlexander V. Chernikov 283b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 284b074b7bbSAlexander V. Chernikov 285b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 2869f7d47b0SAlexander V. Chernikov error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf); 2873b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2883b3a8eb9SGleb Smirnoff 2899f7d47b0SAlexander V. Chernikov if (error == 0) 2909f7d47b0SAlexander V. Chernikov tc->count--; 291b074b7bbSAlexander V. Chernikov 2929f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2933b3a8eb9SGleb Smirnoff 2949f7d47b0SAlexander V. Chernikov ta->flush_entry(tei, &ta_buf); 295ac35ff17SAlexander V. Chernikov 296ac35ff17SAlexander V. Chernikov return (error); 297ac35ff17SAlexander V. Chernikov } 298ac35ff17SAlexander V. Chernikov 299ac35ff17SAlexander V. Chernikov int 300ac35ff17SAlexander V. Chernikov ipfw_modify_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 301ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 302ac35ff17SAlexander V. Chernikov { 303ac35ff17SAlexander V. Chernikov int error; 304ac35ff17SAlexander V. Chernikov 305ac35ff17SAlexander V. Chernikov switch (op3->version) { 306ac35ff17SAlexander V. Chernikov case 0: 307ac35ff17SAlexander V. Chernikov error = ipfw_modify_table_v0(ch, op3, sd); 308ac35ff17SAlexander V. Chernikov break; 309ac35ff17SAlexander V. Chernikov case 1: 310ac35ff17SAlexander V. Chernikov error = ipfw_modify_table_v1(ch, op3, sd); 311ac35ff17SAlexander V. Chernikov break; 312ac35ff17SAlexander V. Chernikov default: 313ac35ff17SAlexander V. Chernikov error = ENOTSUP; 314ac35ff17SAlexander V. Chernikov } 315ac35ff17SAlexander V. Chernikov 316ac35ff17SAlexander V. Chernikov return (error); 317ac35ff17SAlexander V. Chernikov } 318ac35ff17SAlexander V. Chernikov 319ac35ff17SAlexander V. Chernikov /* 320ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 321ac35ff17SAlexander V. Chernikov * Data layout (v0): 322ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ipfw_table_xentry ] 323ac35ff17SAlexander V. Chernikov * 324ac35ff17SAlexander V. Chernikov * Returns 0 on success 325ac35ff17SAlexander V. Chernikov */ 326ac35ff17SAlexander V. Chernikov static int 327ac35ff17SAlexander V. Chernikov ipfw_modify_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 328ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 329ac35ff17SAlexander V. Chernikov { 330ac35ff17SAlexander V. Chernikov ipfw_table_xentry *xent; 331ac35ff17SAlexander V. Chernikov struct tentry_info tei; 332ac35ff17SAlexander V. Chernikov struct tid_info ti; 333ac35ff17SAlexander V. Chernikov int error, hdrlen, read; 334ac35ff17SAlexander V. Chernikov 335ac35ff17SAlexander V. Chernikov hdrlen = offsetof(ipfw_table_xentry, k); 336ac35ff17SAlexander V. Chernikov 337ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 338ac35ff17SAlexander V. Chernikov if (sd->valsize < (sizeof(*op3) + hdrlen)) 339ac35ff17SAlexander V. Chernikov return (EINVAL); 340ac35ff17SAlexander V. Chernikov 341ac35ff17SAlexander V. Chernikov read = sizeof(ip_fw3_opheader); 342ac35ff17SAlexander V. Chernikov 343ac35ff17SAlexander V. Chernikov /* Check if xentry len field is valid */ 344ac35ff17SAlexander V. Chernikov xent = (ipfw_table_xentry *)(op3 + 1); 345ac35ff17SAlexander V. Chernikov if (xent->len < hdrlen || xent->len + read > sd->valsize) 346ac35ff17SAlexander V. Chernikov return (EINVAL); 347ac35ff17SAlexander V. Chernikov 348ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 349ac35ff17SAlexander V. Chernikov tei.paddr = &xent->k; 350ac35ff17SAlexander V. Chernikov tei.masklen = xent->masklen; 351ac35ff17SAlexander V. Chernikov tei.value = xent->value; 352ac35ff17SAlexander V. Chernikov /* Old requests compability */ 353ac35ff17SAlexander V. Chernikov if (xent->type == IPFW_TABLE_CIDR) { 354ac35ff17SAlexander V. Chernikov if (xent->len - hdrlen == sizeof(in_addr_t)) 355ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET; 356ac35ff17SAlexander V. Chernikov else 357ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET6; 358ac35ff17SAlexander V. Chernikov } 359ac35ff17SAlexander V. Chernikov 360ac35ff17SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 361ac35ff17SAlexander V. Chernikov ti.uidx = xent->tbl; 362ac35ff17SAlexander V. Chernikov ti.type = xent->type; 363ac35ff17SAlexander V. Chernikov 364ac35ff17SAlexander V. Chernikov error = (op3->opcode == IP_FW_TABLE_XADD) ? 3651832a7b3SAlexander V. Chernikov add_table_entry(ch, &ti, &tei) : 3661832a7b3SAlexander V. Chernikov del_table_entry(ch, &ti, &tei); 367ac35ff17SAlexander V. Chernikov 368ac35ff17SAlexander V. Chernikov return (error); 369ac35ff17SAlexander V. Chernikov } 370ac35ff17SAlexander V. Chernikov 371ac35ff17SAlexander V. Chernikov /* 372ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 373ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 374ac35ff17SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_obj_tentry ] 375ac35ff17SAlexander V. Chernikov * 376ac35ff17SAlexander V. Chernikov * Returns 0 on success 377ac35ff17SAlexander V. Chernikov */ 378ac35ff17SAlexander V. Chernikov static int 379ac35ff17SAlexander V. Chernikov ipfw_modify_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 380ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 381ac35ff17SAlexander V. Chernikov { 382ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent; 383ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 384ac35ff17SAlexander V. Chernikov struct tentry_info tei; 385ac35ff17SAlexander V. Chernikov struct tid_info ti; 386ac35ff17SAlexander V. Chernikov int error, read; 387ac35ff17SAlexander V. Chernikov 388ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 389ac35ff17SAlexander V. Chernikov if (sd->valsize < (sizeof(*oh) + sizeof(*tent))) 390ac35ff17SAlexander V. Chernikov return (EINVAL); 391ac35ff17SAlexander V. Chernikov 392ac35ff17SAlexander V. Chernikov /* Check if passed data is too long */ 393ac35ff17SAlexander V. Chernikov if (sd->valsize != sd->kavail) 394ac35ff17SAlexander V. Chernikov return (EINVAL); 395ac35ff17SAlexander V. Chernikov 396ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)sd->kbuf; 397ac35ff17SAlexander V. Chernikov 398ac35ff17SAlexander V. Chernikov /* Basic length checks for TLVs */ 399ac35ff17SAlexander V. Chernikov if (oh->ntlv.head.length != sizeof(oh->ntlv)) 400ac35ff17SAlexander V. Chernikov return (EINVAL); 401ac35ff17SAlexander V. Chernikov 402ac35ff17SAlexander V. Chernikov read = sizeof(*oh); 403ac35ff17SAlexander V. Chernikov 404ac35ff17SAlexander V. Chernikov /* Assume tentry may grow to support larger keys */ 405ac35ff17SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 406ac35ff17SAlexander V. Chernikov if (tent->head.length < sizeof(*tent) || 407ac35ff17SAlexander V. Chernikov tent->head.length + read > sd->valsize) 408ac35ff17SAlexander V. Chernikov return (EINVAL); 409ac35ff17SAlexander V. Chernikov 41081d3153dSAlexander V. Chernikov /* Convert data into kernel request objects */ 411ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 412ac35ff17SAlexander V. Chernikov tei.paddr = &tent->k; 413ac35ff17SAlexander V. Chernikov tei.subtype = tent->subtype; 414ac35ff17SAlexander V. Chernikov tei.masklen = tent->masklen; 41581d3153dSAlexander V. Chernikov if (tent->head.flags & IPFW_TF_UPDATE) 416ac35ff17SAlexander V. Chernikov tei.flags |= TEI_FLAGS_UPDATE; 417ac35ff17SAlexander V. Chernikov tei.value = tent->value; 418ac35ff17SAlexander V. Chernikov 41981d3153dSAlexander V. Chernikov objheader_to_ti(oh, &ti); 420ac35ff17SAlexander V. Chernikov ti.type = oh->ntlv.type; 42181d3153dSAlexander V. Chernikov ti.uidx = tent->idx; 422ac35ff17SAlexander V. Chernikov 423ac35ff17SAlexander V. Chernikov error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ? 4241832a7b3SAlexander V. Chernikov add_table_entry(ch, &ti, &tei) : 4251832a7b3SAlexander V. Chernikov del_table_entry(ch, &ti, &tei); 426ac35ff17SAlexander V. Chernikov 427ac35ff17SAlexander V. Chernikov return (error); 428ac35ff17SAlexander V. Chernikov } 429ac35ff17SAlexander V. Chernikov 43081d3153dSAlexander V. Chernikov /* 43181d3153dSAlexander V. Chernikov * Looks up an entry in given table. 43281d3153dSAlexander V. Chernikov * Data layout (v0)(current): 43381d3153dSAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_obj_tentry ] 43481d3153dSAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_obj_tentry ] 43581d3153dSAlexander V. Chernikov * 43681d3153dSAlexander V. Chernikov * Returns 0 on success 43781d3153dSAlexander V. Chernikov */ 43881d3153dSAlexander V. Chernikov int 43981d3153dSAlexander V. Chernikov ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 44081d3153dSAlexander V. Chernikov struct sockopt_data *sd) 44181d3153dSAlexander V. Chernikov { 44281d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 44381d3153dSAlexander V. Chernikov ipfw_obj_header *oh; 44481d3153dSAlexander V. Chernikov struct tid_info ti; 44581d3153dSAlexander V. Chernikov struct table_config *tc; 44681d3153dSAlexander V. Chernikov struct table_algo *ta; 44781d3153dSAlexander V. Chernikov struct table_info *kti; 44881d3153dSAlexander V. Chernikov struct namedobj_instance *ni; 44981d3153dSAlexander V. Chernikov int error, plen; 45081d3153dSAlexander V. Chernikov void *paddr; 45181d3153dSAlexander V. Chernikov size_t sz; 45281d3153dSAlexander V. Chernikov 45381d3153dSAlexander V. Chernikov /* Check minimum header size */ 45481d3153dSAlexander V. Chernikov sz = sizeof(*oh) + sizeof(*tent); 45581d3153dSAlexander V. Chernikov if (sd->valsize != sz) 45681d3153dSAlexander V. Chernikov return (EINVAL); 45781d3153dSAlexander V. Chernikov 45881d3153dSAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 45981d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 46081d3153dSAlexander V. Chernikov 46181d3153dSAlexander V. Chernikov /* Basic length checks for TLVs */ 46281d3153dSAlexander V. Chernikov if (oh->ntlv.head.length != sizeof(oh->ntlv)) 46381d3153dSAlexander V. Chernikov return (EINVAL); 46481d3153dSAlexander V. Chernikov 46581d3153dSAlexander V. Chernikov objheader_to_ti(oh, &ti); 46681d3153dSAlexander V. Chernikov ti.type = oh->ntlv.type; 46781d3153dSAlexander V. Chernikov ti.uidx = tent->idx; 46881d3153dSAlexander V. Chernikov 46981d3153dSAlexander V. Chernikov IPFW_UH_RLOCK(ch); 47081d3153dSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 47181d3153dSAlexander V. Chernikov 47281d3153dSAlexander V. Chernikov /* 47381d3153dSAlexander V. Chernikov * Find existing table and check its type . 47481d3153dSAlexander V. Chernikov */ 47581d3153dSAlexander V. Chernikov ta = NULL; 47681d3153dSAlexander V. Chernikov if ((tc = find_table(ni, &ti)) == NULL) { 47781d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 47881d3153dSAlexander V. Chernikov return (ESRCH); 47981d3153dSAlexander V. Chernikov } 48081d3153dSAlexander V. Chernikov 48181d3153dSAlexander V. Chernikov /* check table type */ 48281d3153dSAlexander V. Chernikov if (tc->no.type != ti.type) { 48381d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 48481d3153dSAlexander V. Chernikov return (EINVAL); 48581d3153dSAlexander V. Chernikov } 48681d3153dSAlexander V. Chernikov 48781d3153dSAlexander V. Chernikov /* Check lookup key for validness */ 48881d3153dSAlexander V. Chernikov plen = 0; 48981d3153dSAlexander V. Chernikov paddr = &tent->k; 49081d3153dSAlexander V. Chernikov switch (ti.type) 49181d3153dSAlexander V. Chernikov { 49281d3153dSAlexander V. Chernikov case IPFW_TABLE_CIDR: 49381d3153dSAlexander V. Chernikov if (tent->subtype == AF_INET) 49481d3153dSAlexander V. Chernikov plen = sizeof(struct in_addr); 49581d3153dSAlexander V. Chernikov else if (tent->subtype == AF_INET6) 49681d3153dSAlexander V. Chernikov plen = sizeof(struct in6_addr); 49781d3153dSAlexander V. Chernikov else { 49881d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 49981d3153dSAlexander V. Chernikov return (EINVAL); 50081d3153dSAlexander V. Chernikov } 50181d3153dSAlexander V. Chernikov break; 50281d3153dSAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 50381d3153dSAlexander V. Chernikov /* Check key first */ 50481d3153dSAlexander V. Chernikov plen = sizeof(tent->k.iface); 50581d3153dSAlexander V. Chernikov if (strnlen(tent->k.iface, plen) == plen) { 50681d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 50781d3153dSAlexander V. Chernikov return (EINVAL); 50881d3153dSAlexander V. Chernikov } 50981d3153dSAlexander V. Chernikov 51081d3153dSAlexander V. Chernikov break; 51181d3153dSAlexander V. Chernikov default: 51281d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 51381d3153dSAlexander V. Chernikov return (ENOTSUP); 51481d3153dSAlexander V. Chernikov } 51581d3153dSAlexander V. Chernikov kti = KIDX_TO_TI(ch, tc->no.kidx); 51681d3153dSAlexander V. Chernikov ta = tc->ta; 51781d3153dSAlexander V. Chernikov 51881d3153dSAlexander V. Chernikov error = ta->find_tentry(tc->astate, kti, paddr, plen, tent); 51981d3153dSAlexander V. Chernikov 52081d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 52181d3153dSAlexander V. Chernikov 52281d3153dSAlexander V. Chernikov return (error); 52381d3153dSAlexander V. Chernikov } 52481d3153dSAlexander V. Chernikov 525ac35ff17SAlexander V. Chernikov int 526ac35ff17SAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 527ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 528ac35ff17SAlexander V. Chernikov { 529ac35ff17SAlexander V. Chernikov int error; 530ac35ff17SAlexander V. Chernikov struct _ipfw_obj_header *oh; 531ac35ff17SAlexander V. Chernikov struct tid_info ti; 532ac35ff17SAlexander V. Chernikov 533ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh)) 534ac35ff17SAlexander V. Chernikov return (EINVAL); 535ac35ff17SAlexander V. Chernikov 536ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)op3; 537ac35ff17SAlexander V. Chernikov objheader_to_ti(oh, &ti); 538ac35ff17SAlexander V. Chernikov 5391832a7b3SAlexander V. Chernikov if (op3->opcode == IP_FW_TABLE_XDESTROY) 540ac35ff17SAlexander V. Chernikov error = destroy_table(ch, &ti); 5411832a7b3SAlexander V. Chernikov else if (op3->opcode == IP_FW_TABLE_XFLUSH) 542ac35ff17SAlexander V. Chernikov error = flush_table(ch, &ti); 543ac35ff17SAlexander V. Chernikov else 544ac35ff17SAlexander V. Chernikov return (ENOTSUP); 545ac35ff17SAlexander V. Chernikov 546ac35ff17SAlexander V. Chernikov return (error); 5473b3a8eb9SGleb Smirnoff } 5483b3a8eb9SGleb Smirnoff 549b074b7bbSAlexander V. Chernikov /* 5509f7d47b0SAlexander V. Chernikov * Flushes all entries in given table. 551ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 552ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 553ac35ff17SAlexander V. Chernikov * 554ac35ff17SAlexander V. Chernikov * Returns 0 on success 555b074b7bbSAlexander V. Chernikov */ 5561832a7b3SAlexander V. Chernikov int 557ac35ff17SAlexander V. Chernikov flush_table(struct ip_fw_chain *ch, struct tid_info *ti) 5583b3a8eb9SGleb Smirnoff { 559b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 560b074b7bbSAlexander V. Chernikov struct table_config *tc; 5619f7d47b0SAlexander V. Chernikov struct table_algo *ta; 5629f7d47b0SAlexander V. Chernikov struct table_info ti_old, ti_new, *tablestate; 5639f7d47b0SAlexander V. Chernikov void *astate_old, *astate_new; 564b074b7bbSAlexander V. Chernikov int error; 565b074b7bbSAlexander V. Chernikov uint16_t kidx; 5663b3a8eb9SGleb Smirnoff 5673b3a8eb9SGleb Smirnoff /* 5689f7d47b0SAlexander V. Chernikov * Stage 1: save table algoritm. 569b074b7bbSAlexander V. Chernikov * Reference found table to ensure it won't disappear. 5703b3a8eb9SGleb Smirnoff */ 571b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 572b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 573b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 574b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 575b074b7bbSAlexander V. Chernikov return (ESRCH); 576b074b7bbSAlexander V. Chernikov } 5779f7d47b0SAlexander V. Chernikov ta = tc->ta; 578b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 579b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 5803b3a8eb9SGleb Smirnoff 581b074b7bbSAlexander V. Chernikov /* 5829f7d47b0SAlexander V. Chernikov * Stage 2: allocate new table instance using same algo. 5839490a627SAlexander V. Chernikov * TODO: pass startup parametes somehow. 584b074b7bbSAlexander V. Chernikov */ 5859f7d47b0SAlexander V. Chernikov memset(&ti_new, 0, sizeof(struct table_info)); 5869490a627SAlexander V. Chernikov if ((error = ta->init(&astate_new, &ti_new, NULL)) != 0) { 587b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 588b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 589b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 590b074b7bbSAlexander V. Chernikov return (error); 591b074b7bbSAlexander V. Chernikov } 592b074b7bbSAlexander V. Chernikov 593b074b7bbSAlexander V. Chernikov /* 594b074b7bbSAlexander V. Chernikov * Stage 3: swap old state pointers with newly-allocated ones. 595b074b7bbSAlexander V. Chernikov * Decrease refcount. 596b074b7bbSAlexander V. Chernikov */ 597b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 598b074b7bbSAlexander V. Chernikov 599b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 600b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 6019f7d47b0SAlexander V. Chernikov tablestate = (struct table_info *)ch->tablestate; 602b074b7bbSAlexander V. Chernikov 6039f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 6049f7d47b0SAlexander V. Chernikov ti_old = tablestate[kidx]; 6059f7d47b0SAlexander V. Chernikov tablestate[kidx] = ti_new; 6069f7d47b0SAlexander V. Chernikov IPFW_WUNLOCK(ch); 607b074b7bbSAlexander V. Chernikov 6089f7d47b0SAlexander V. Chernikov astate_old = tc->astate; 6099f7d47b0SAlexander V. Chernikov tc->astate = astate_new; 6109f7d47b0SAlexander V. Chernikov tc->ti = ti_new; 6119f7d47b0SAlexander V. Chernikov tc->count = 0; 612b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 613b074b7bbSAlexander V. Chernikov 614b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 6153b3a8eb9SGleb Smirnoff 616b074b7bbSAlexander V. Chernikov /* 617b074b7bbSAlexander V. Chernikov * Stage 4: perform real flush. 618b074b7bbSAlexander V. Chernikov */ 6199f7d47b0SAlexander V. Chernikov ta->destroy(astate_old, &ti_old); 6203b3a8eb9SGleb Smirnoff 6213b3a8eb9SGleb Smirnoff return (0); 6223b3a8eb9SGleb Smirnoff } 6233b3a8eb9SGleb Smirnoff 624b074b7bbSAlexander V. Chernikov /* 6259f7d47b0SAlexander V. Chernikov * Destroys table specified by @ti. 626ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 627ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 628ac35ff17SAlexander V. Chernikov * 629ac35ff17SAlexander V. Chernikov * Returns 0 on success 630b074b7bbSAlexander V. Chernikov */ 631ac35ff17SAlexander V. Chernikov static int 632ac35ff17SAlexander V. Chernikov destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) 633b074b7bbSAlexander V. Chernikov { 634b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 635b074b7bbSAlexander V. Chernikov struct table_config *tc; 636b074b7bbSAlexander V. Chernikov 637b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 638b074b7bbSAlexander V. Chernikov 639b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 640b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 641b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 642b074b7bbSAlexander V. Chernikov return (ESRCH); 643b074b7bbSAlexander V. Chernikov } 644b074b7bbSAlexander V. Chernikov 6459f7d47b0SAlexander V. Chernikov /* Do not permit destroying referenced tables */ 6469f7d47b0SAlexander V. Chernikov if (tc->no.refcnt > 0) { 647b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 648b074b7bbSAlexander V. Chernikov return (EBUSY); 649b074b7bbSAlexander V. Chernikov } 650b074b7bbSAlexander V. Chernikov 651b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 652b074b7bbSAlexander V. Chernikov unlink_table(ch, tc); 653b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 654b074b7bbSAlexander V. Chernikov 655b074b7bbSAlexander V. Chernikov /* Free obj index */ 656ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0) 657b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 658b074b7bbSAlexander V. Chernikov tc->no.kidx, tc->tablename); 659b074b7bbSAlexander V. Chernikov 660b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 661b074b7bbSAlexander V. Chernikov 662b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 663b074b7bbSAlexander V. Chernikov 664b074b7bbSAlexander V. Chernikov return (0); 665b074b7bbSAlexander V. Chernikov } 666b074b7bbSAlexander V. Chernikov 667b074b7bbSAlexander V. Chernikov static void 668b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, 669b074b7bbSAlexander V. Chernikov void *arg) 670b074b7bbSAlexander V. Chernikov { 671b074b7bbSAlexander V. Chernikov 672b074b7bbSAlexander V. Chernikov unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); 673ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, no->kidx) != 0) 674b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 675b074b7bbSAlexander V. Chernikov no->kidx, no->name); 676b074b7bbSAlexander V. Chernikov free_table_config(ni, (struct table_config *)no); 677b074b7bbSAlexander V. Chernikov } 678b074b7bbSAlexander V. Chernikov 6793b3a8eb9SGleb Smirnoff void 6803b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch) 6813b3a8eb9SGleb Smirnoff { 6823b3a8eb9SGleb Smirnoff 683b074b7bbSAlexander V. Chernikov /* Remove all tables from working set */ 684b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 685b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 686b074b7bbSAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); 687b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 688b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 6893b3a8eb9SGleb Smirnoff 6903b3a8eb9SGleb Smirnoff /* Free pointers itself */ 6919f7d47b0SAlexander V. Chernikov free(ch->tablestate, M_IPFW); 6929f7d47b0SAlexander V. Chernikov 6939f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(ch); 694b074b7bbSAlexander V. Chernikov 695b074b7bbSAlexander V. Chernikov ipfw_objhash_destroy(CHAIN_TO_NI(ch)); 696b074b7bbSAlexander V. Chernikov free(CHAIN_TO_TCFG(ch), M_IPFW); 6973b3a8eb9SGleb Smirnoff } 6983b3a8eb9SGleb Smirnoff 6993b3a8eb9SGleb Smirnoff int 7003b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch) 7013b3a8eb9SGleb Smirnoff { 702b074b7bbSAlexander V. Chernikov struct tables_config *tcfg; 703b074b7bbSAlexander V. Chernikov 7043b3a8eb9SGleb Smirnoff /* Allocate pointers */ 7059f7d47b0SAlexander V. Chernikov ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), 7069f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 707b074b7bbSAlexander V. Chernikov 708b074b7bbSAlexander V. Chernikov tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); 709b074b7bbSAlexander V. Chernikov tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); 710b074b7bbSAlexander V. Chernikov ch->tblcfg = tcfg; 711b074b7bbSAlexander V. Chernikov 7129f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(ch); 7139f7d47b0SAlexander V. Chernikov 7143b3a8eb9SGleb Smirnoff return (0); 7153b3a8eb9SGleb Smirnoff } 7163b3a8eb9SGleb Smirnoff 7173b3a8eb9SGleb Smirnoff int 7183b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) 7193b3a8eb9SGleb Smirnoff { 7203b3a8eb9SGleb Smirnoff unsigned int ntables_old, tbl; 721b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 7229f7d47b0SAlexander V. Chernikov void *new_idx, *old_tablestate, *tablestate; 723b074b7bbSAlexander V. Chernikov int new_blocks; 7243b3a8eb9SGleb Smirnoff 7253b3a8eb9SGleb Smirnoff /* Check new value for validity */ 7263b3a8eb9SGleb Smirnoff if (ntables > IPFW_TABLES_MAX) 7273b3a8eb9SGleb Smirnoff ntables = IPFW_TABLES_MAX; 7283b3a8eb9SGleb Smirnoff 7293b3a8eb9SGleb Smirnoff /* Allocate new pointers */ 7309f7d47b0SAlexander V. Chernikov tablestate = malloc(ntables * sizeof(struct table_info), 7319f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 7329f7d47b0SAlexander V. Chernikov 733b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); 7343b3a8eb9SGleb Smirnoff 7359f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 7363b3a8eb9SGleb Smirnoff 7373b3a8eb9SGleb Smirnoff tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables; 738b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 739b074b7bbSAlexander V. Chernikov 7409f7d47b0SAlexander V. Chernikov /* Temporary restrict decreasing max_tables */ 7419f7d47b0SAlexander V. Chernikov if (ntables < V_fw_tables_max) { 7429f7d47b0SAlexander V. Chernikov 7439f7d47b0SAlexander V. Chernikov /* 7449f7d47b0SAlexander V. Chernikov * FIXME: Check if we really can shrink 7459f7d47b0SAlexander V. Chernikov */ 7469f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 747b074b7bbSAlexander V. Chernikov return (EINVAL); 748b074b7bbSAlexander V. Chernikov } 7493b3a8eb9SGleb Smirnoff 7509f7d47b0SAlexander V. Chernikov /* Copy table info/indices */ 7519f7d47b0SAlexander V. Chernikov memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl); 7529f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks); 7533b3a8eb9SGleb Smirnoff 7549f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 7559f7d47b0SAlexander V. Chernikov 7569f7d47b0SAlexander V. Chernikov /* Change pointers */ 7579f7d47b0SAlexander V. Chernikov old_tablestate = ch->tablestate; 7589f7d47b0SAlexander V. Chernikov ch->tablestate = tablestate; 7599f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks); 7603b3a8eb9SGleb Smirnoff 7613b3a8eb9SGleb Smirnoff ntables_old = V_fw_tables_max; 7623b3a8eb9SGleb Smirnoff V_fw_tables_max = ntables; 7633b3a8eb9SGleb Smirnoff 7643b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 7659f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 7663b3a8eb9SGleb Smirnoff 7673b3a8eb9SGleb Smirnoff /* Free old pointers */ 7689f7d47b0SAlexander V. Chernikov free(old_tablestate, M_IPFW); 769b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 7703b3a8eb9SGleb Smirnoff 7713b3a8eb9SGleb Smirnoff return (0); 7723b3a8eb9SGleb Smirnoff } 7733b3a8eb9SGleb Smirnoff 7743b3a8eb9SGleb Smirnoff int 7753b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 7763b3a8eb9SGleb Smirnoff uint32_t *val) 7773b3a8eb9SGleb Smirnoff { 7789f7d47b0SAlexander V. Chernikov struct table_info *ti; 7793b3a8eb9SGleb Smirnoff 7809f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 7819f7d47b0SAlexander V. Chernikov 7829f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, &addr, sizeof(in_addr_t), val)); 7833b3a8eb9SGleb Smirnoff } 7849f7d47b0SAlexander V. Chernikov 7859f7d47b0SAlexander V. Chernikov int 7869f7d47b0SAlexander V. Chernikov ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, 7879f7d47b0SAlexander V. Chernikov void *paddr, uint32_t *val) 7889f7d47b0SAlexander V. Chernikov { 7899f7d47b0SAlexander V. Chernikov struct table_info *ti; 7909f7d47b0SAlexander V. Chernikov 7919f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 7929f7d47b0SAlexander V. Chernikov 7939f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, paddr, plen, val)); 7949f7d47b0SAlexander V. Chernikov } 7959f7d47b0SAlexander V. Chernikov 7969f7d47b0SAlexander V. Chernikov /* 7979f7d47b0SAlexander V. Chernikov * Info/List/dump support for tables. 7989f7d47b0SAlexander V. Chernikov * 7999f7d47b0SAlexander V. Chernikov */ 8009f7d47b0SAlexander V. Chernikov 801f1220db8SAlexander V. Chernikov /* 802d3a4f924SAlexander V. Chernikov * High-level 'get' cmds sysctl handlers 803d3a4f924SAlexander V. Chernikov */ 804d3a4f924SAlexander V. Chernikov 805d3a4f924SAlexander V. Chernikov /* 806d3a4f924SAlexander V. Chernikov * Get buffer size needed to list info for all tables. 807ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 808d3a4f924SAlexander V. Chernikov * Request: [ empty ], size = sizeof(ipfw_obj_lheader) 809d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ] 810d3a4f924SAlexander V. Chernikov * 811d3a4f924SAlexander V. Chernikov * Returns 0 on success 812f1220db8SAlexander V. Chernikov */ 813f1220db8SAlexander V. Chernikov int 8142d99a349SAlexander V. Chernikov ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 815f1220db8SAlexander V. Chernikov { 816f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 817f1220db8SAlexander V. Chernikov 8182d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 8192d99a349SAlexander V. Chernikov if (olh == NULL) 820d3a4f924SAlexander V. Chernikov return (EINVAL); 821d3a4f924SAlexander V. Chernikov 822f1220db8SAlexander V. Chernikov olh->size = sizeof(*olh); /* Make export_table store needed size */ 823f1220db8SAlexander V. Chernikov 824f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 8252d99a349SAlexander V. Chernikov export_tables(ch, olh, sd); 826f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 827f1220db8SAlexander V. Chernikov 8282d99a349SAlexander V. Chernikov return (0); 829f1220db8SAlexander V. Chernikov } 830f1220db8SAlexander V. Chernikov 831d3a4f924SAlexander V. Chernikov /* 832d3a4f924SAlexander V. Chernikov * Lists all tables currently available in kernel. 833ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 834d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 835d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ] 836d3a4f924SAlexander V. Chernikov * 837d3a4f924SAlexander V. Chernikov * Returns 0 on success 838d3a4f924SAlexander V. Chernikov */ 839f1220db8SAlexander V. Chernikov int 8402d99a349SAlexander V. Chernikov ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 841f1220db8SAlexander V. Chernikov { 842f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 843d3a4f924SAlexander V. Chernikov uint32_t sz; 844f1220db8SAlexander V. Chernikov int error; 845f1220db8SAlexander V. Chernikov 8462d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 8472d99a349SAlexander V. Chernikov if (olh == NULL) 848d3a4f924SAlexander V. Chernikov return (EINVAL); 849d3a4f924SAlexander V. Chernikov 850f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 851f1220db8SAlexander V. Chernikov sz = ipfw_objhash_count(CHAIN_TO_NI(ch)); 8522d99a349SAlexander V. Chernikov 8532d99a349SAlexander V. Chernikov if (sd->valsize < sz) { 8542d99a349SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 8552d99a349SAlexander V. Chernikov return (ENOMEM); 8562d99a349SAlexander V. Chernikov } 8572d99a349SAlexander V. Chernikov 8582d99a349SAlexander V. Chernikov error = export_tables(ch, olh, sd); 859f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 860f1220db8SAlexander V. Chernikov 861f1220db8SAlexander V. Chernikov return (error); 862f1220db8SAlexander V. Chernikov } 863f1220db8SAlexander V. Chernikov 864f1220db8SAlexander V. Chernikov /* 8652d99a349SAlexander V. Chernikov * Store table info to buffer provided by @sd. 866ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 867d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info(empty)] 868d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ] 869d3a4f924SAlexander V. Chernikov * 870d3a4f924SAlexander V. Chernikov * Returns 0 on success. 871d3a4f924SAlexander V. Chernikov */ 872d3a4f924SAlexander V. Chernikov int 8732d99a349SAlexander V. Chernikov ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd) 874d3a4f924SAlexander V. Chernikov { 875d3a4f924SAlexander V. Chernikov struct _ipfw_obj_header *oh; 876d3a4f924SAlexander V. Chernikov struct table_config *tc; 877d3a4f924SAlexander V. Chernikov struct tid_info ti; 878d3a4f924SAlexander V. Chernikov size_t sz; 879d3a4f924SAlexander V. Chernikov 880d3a4f924SAlexander V. Chernikov sz = sizeof(*oh) + sizeof(ipfw_xtable_info); 8812d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 8822d99a349SAlexander V. Chernikov if (oh == NULL) 883d3a4f924SAlexander V. Chernikov return (EINVAL); 884d3a4f924SAlexander V. Chernikov 885d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 886d3a4f924SAlexander V. Chernikov 887d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 888d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 889d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 890d3a4f924SAlexander V. Chernikov return (ESRCH); 891d3a4f924SAlexander V. Chernikov } 892d3a4f924SAlexander V. Chernikov 893ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, (ipfw_xtable_info *)(oh + 1)); 894d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 895d3a4f924SAlexander V. Chernikov 8962d99a349SAlexander V. Chernikov return (0); 897d3a4f924SAlexander V. Chernikov } 898d3a4f924SAlexander V. Chernikov 899f1220db8SAlexander V. Chernikov struct dump_args { 900f1220db8SAlexander V. Chernikov struct table_info *ti; 901f1220db8SAlexander V. Chernikov struct table_config *tc; 9022d99a349SAlexander V. Chernikov struct sockopt_data *sd; 903f1220db8SAlexander V. Chernikov uint32_t cnt; 904f1220db8SAlexander V. Chernikov uint16_t uidx; 90581d3153dSAlexander V. Chernikov int error; 9062d99a349SAlexander V. Chernikov ipfw_table_entry *ent; 9072d99a349SAlexander V. Chernikov uint32_t size; 90881d3153dSAlexander V. Chernikov ipfw_obj_tentry tent; 909f1220db8SAlexander V. Chernikov }; 910f1220db8SAlexander V. Chernikov 911f1220db8SAlexander V. Chernikov int 9122d99a349SAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 9132d99a349SAlexander V. Chernikov struct sockopt_data *sd) 914f1220db8SAlexander V. Chernikov { 915d3a4f924SAlexander V. Chernikov int error; 916d3a4f924SAlexander V. Chernikov 917d3a4f924SAlexander V. Chernikov switch (op3->version) { 918d3a4f924SAlexander V. Chernikov case 0: 9192d99a349SAlexander V. Chernikov error = ipfw_dump_table_v0(ch, sd); 920d3a4f924SAlexander V. Chernikov break; 921d3a4f924SAlexander V. Chernikov case 1: 9222d99a349SAlexander V. Chernikov error = ipfw_dump_table_v1(ch, sd); 923d3a4f924SAlexander V. Chernikov break; 924d3a4f924SAlexander V. Chernikov default: 925d3a4f924SAlexander V. Chernikov error = ENOTSUP; 926d3a4f924SAlexander V. Chernikov } 927d3a4f924SAlexander V. Chernikov 928d3a4f924SAlexander V. Chernikov return (error); 929d3a4f924SAlexander V. Chernikov } 930d3a4f924SAlexander V. Chernikov 931d3a4f924SAlexander V. Chernikov /* 932d3a4f924SAlexander V. Chernikov * Dumps all table data 933ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 9342d99a349SAlexander V. Chernikov * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size 93581d3153dSAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ] 936d3a4f924SAlexander V. Chernikov * 937d3a4f924SAlexander V. Chernikov * Returns 0 on success 938d3a4f924SAlexander V. Chernikov */ 939d3a4f924SAlexander V. Chernikov static int 9402d99a349SAlexander V. Chernikov ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd) 941d3a4f924SAlexander V. Chernikov { 942f1220db8SAlexander V. Chernikov struct _ipfw_obj_header *oh; 943f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 944f1220db8SAlexander V. Chernikov struct tid_info ti; 945f1220db8SAlexander V. Chernikov struct table_config *tc; 946f1220db8SAlexander V. Chernikov struct table_algo *ta; 947f1220db8SAlexander V. Chernikov struct dump_args da; 948d3a4f924SAlexander V. Chernikov uint32_t sz; 949f1220db8SAlexander V. Chernikov 9502d99a349SAlexander V. Chernikov sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 9512d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 9522d99a349SAlexander V. Chernikov if (oh == NULL) 953d3a4f924SAlexander V. Chernikov return (EINVAL); 954d3a4f924SAlexander V. Chernikov 9552d99a349SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 956d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 957f1220db8SAlexander V. Chernikov 958f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 959f1220db8SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 960f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 961f1220db8SAlexander V. Chernikov return (ESRCH); 962f1220db8SAlexander V. Chernikov } 963ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, i); 9642d99a349SAlexander V. Chernikov sz = tc->count; 9652d99a349SAlexander V. Chernikov 96681d3153dSAlexander V. Chernikov if (sd->valsize < sz + tc->count * sizeof(ipfw_obj_tentry)) { 9672d99a349SAlexander V. Chernikov 9682d99a349SAlexander V. Chernikov /* 9692d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 9702d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 9712d99a349SAlexander V. Chernikov * relevant table info including size, so we 9722d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 9732d99a349SAlexander V. Chernikov */ 974f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 9752d99a349SAlexander V. Chernikov return (ENOMEM); 976f1220db8SAlexander V. Chernikov } 977f1220db8SAlexander V. Chernikov 978f1220db8SAlexander V. Chernikov /* 979f1220db8SAlexander V. Chernikov * Do the actual dump in eXtended format 980f1220db8SAlexander V. Chernikov */ 981d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 982f1220db8SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 983f1220db8SAlexander V. Chernikov da.tc = tc; 9842d99a349SAlexander V. Chernikov da.sd = sd; 985f1220db8SAlexander V. Chernikov 986f1220db8SAlexander V. Chernikov ta = tc->ta; 987f1220db8SAlexander V. Chernikov 98881d3153dSAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_tentry, &da); 989f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 990f1220db8SAlexander V. Chernikov 99181d3153dSAlexander V. Chernikov return (da.error); 992f1220db8SAlexander V. Chernikov } 993f1220db8SAlexander V. Chernikov 994d3a4f924SAlexander V. Chernikov /* 995d3a4f924SAlexander V. Chernikov * Dumps all table data 9962d99a349SAlexander V. Chernikov * Data layout (version 0)(legacy): 997d3a4f924SAlexander V. Chernikov * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE() 998d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_xtable ipfw_table_xentry x N ] 999d3a4f924SAlexander V. Chernikov * 1000d3a4f924SAlexander V. Chernikov * Returns 0 on success 1001d3a4f924SAlexander V. Chernikov */ 1002d3a4f924SAlexander V. Chernikov static int 10032d99a349SAlexander V. Chernikov ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd) 1004d3a4f924SAlexander V. Chernikov { 1005d3a4f924SAlexander V. Chernikov ipfw_xtable *xtbl; 1006d3a4f924SAlexander V. Chernikov struct tid_info ti; 1007d3a4f924SAlexander V. Chernikov struct table_config *tc; 1008d3a4f924SAlexander V. Chernikov struct table_algo *ta; 1009d3a4f924SAlexander V. Chernikov struct dump_args da; 1010d3a4f924SAlexander V. Chernikov size_t sz; 1011d3a4f924SAlexander V. Chernikov 10122d99a349SAlexander V. Chernikov xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable)); 10132d99a349SAlexander V. Chernikov if (xtbl == NULL) 1014d3a4f924SAlexander V. Chernikov return (EINVAL); 1015d3a4f924SAlexander V. Chernikov 1016d3a4f924SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 1017d3a4f924SAlexander V. Chernikov ti.uidx = xtbl->tbl; 1018d3a4f924SAlexander V. Chernikov 1019d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 1020d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 1021d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1022d3a4f924SAlexander V. Chernikov return (0); 1023d3a4f924SAlexander V. Chernikov } 1024d3a4f924SAlexander V. Chernikov sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); 10252d99a349SAlexander V. Chernikov 10262d99a349SAlexander V. Chernikov xtbl->cnt = tc->count; 10272d99a349SAlexander V. Chernikov xtbl->size = sz; 10282d99a349SAlexander V. Chernikov xtbl->type = tc->no.type; 10292d99a349SAlexander V. Chernikov xtbl->tbl = ti.uidx; 10302d99a349SAlexander V. Chernikov 10312d99a349SAlexander V. Chernikov if (sd->valsize < sz) { 10322d99a349SAlexander V. Chernikov 10332d99a349SAlexander V. Chernikov /* 10342d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 10352d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 10362d99a349SAlexander V. Chernikov * relevant table info including size, so we 10372d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 10382d99a349SAlexander V. Chernikov */ 1039d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 10402d99a349SAlexander V. Chernikov return (ENOMEM); 1041d3a4f924SAlexander V. Chernikov } 1042d3a4f924SAlexander V. Chernikov 1043d3a4f924SAlexander V. Chernikov /* Do the actual dump in eXtended format */ 1044d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 1045d3a4f924SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 1046d3a4f924SAlexander V. Chernikov da.tc = tc; 10472d99a349SAlexander V. Chernikov da.sd = sd; 10482d99a349SAlexander V. Chernikov 1049d3a4f924SAlexander V. Chernikov ta = tc->ta; 1050d3a4f924SAlexander V. Chernikov 1051d3a4f924SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 1052d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1053d3a4f924SAlexander V. Chernikov 10542d99a349SAlexander V. Chernikov return (0); 1055d3a4f924SAlexander V. Chernikov } 1056d3a4f924SAlexander V. Chernikov 1057d3a4f924SAlexander V. Chernikov /* 10589490a627SAlexander V. Chernikov * Creates new table. 1059ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 10609490a627SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 10619490a627SAlexander V. Chernikov * 10629490a627SAlexander V. Chernikov * Returns 0 on success 10639490a627SAlexander V. Chernikov */ 10649490a627SAlexander V. Chernikov int 1065ac35ff17SAlexander V. Chernikov ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 1066ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 10679490a627SAlexander V. Chernikov { 10689490a627SAlexander V. Chernikov struct _ipfw_obj_header *oh; 10699490a627SAlexander V. Chernikov ipfw_xtable_info *i; 10709490a627SAlexander V. Chernikov char *tname, *aname; 10719490a627SAlexander V. Chernikov struct tid_info ti; 10729490a627SAlexander V. Chernikov struct namedobj_instance *ni; 10739490a627SAlexander V. Chernikov struct table_config *tc; 10749490a627SAlexander V. Chernikov struct table_algo *ta; 10759490a627SAlexander V. Chernikov uint16_t kidx; 10769490a627SAlexander V. Chernikov 1077ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info)) 10789490a627SAlexander V. Chernikov return (EINVAL); 10799490a627SAlexander V. Chernikov 1080ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)sd->kbuf; 10819490a627SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 10829490a627SAlexander V. Chernikov 10839490a627SAlexander V. Chernikov /* 10849490a627SAlexander V. Chernikov * Verify user-supplied strings. 10852d99a349SAlexander V. Chernikov * Check for null-terminated/zero-length strings/ 10869490a627SAlexander V. Chernikov */ 1087ac35ff17SAlexander V. Chernikov tname = oh->ntlv.name; 10889490a627SAlexander V. Chernikov aname = i->algoname; 1089ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(tname) != 0 || 10909490a627SAlexander V. Chernikov strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname)) 10919490a627SAlexander V. Chernikov return (EINVAL); 10929490a627SAlexander V. Chernikov 10939490a627SAlexander V. Chernikov if (aname[0] == '\0') { 10949490a627SAlexander V. Chernikov /* Use default algorithm */ 10959490a627SAlexander V. Chernikov aname = NULL; 10969490a627SAlexander V. Chernikov } 10979490a627SAlexander V. Chernikov 10989490a627SAlexander V. Chernikov objheader_to_ti(oh, &ti); 1099ac35ff17SAlexander V. Chernikov ti.type = i->type; 11009490a627SAlexander V. Chernikov 11019490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 11029490a627SAlexander V. Chernikov 11039490a627SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 11049490a627SAlexander V. Chernikov if ((tc = find_table(ni, &ti)) != NULL) { 11059490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 11069490a627SAlexander V. Chernikov return (EEXIST); 11079490a627SAlexander V. Chernikov } 11089490a627SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(ch), &ti, aname); 11099490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 11109490a627SAlexander V. Chernikov 11119490a627SAlexander V. Chernikov if (ta == NULL) 11129490a627SAlexander V. Chernikov return (ENOTSUP); 11139490a627SAlexander V. Chernikov 11149490a627SAlexander V. Chernikov if ((tc = alloc_table_config(ni, &ti, ta, aname)) == NULL) 11159490a627SAlexander V. Chernikov return (ENOMEM); 1116ac35ff17SAlexander V. Chernikov /* TODO: move inside alloc_table_config() */ 1117ac35ff17SAlexander V. Chernikov tc->vtype = i->vtype; 11189490a627SAlexander V. Chernikov 11199490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1120ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) { 11219490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 11229490a627SAlexander V. Chernikov printf("Unable to allocate table index for table %s in set %u." 11239490a627SAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 11249490a627SAlexander V. Chernikov tname, ti.set); 11259490a627SAlexander V. Chernikov free_table_config(ni, tc); 11269490a627SAlexander V. Chernikov return (EBUSY); 11279490a627SAlexander V. Chernikov } 11289490a627SAlexander V. Chernikov 11299490a627SAlexander V. Chernikov tc->no.kidx = kidx; 11309490a627SAlexander V. Chernikov 11319490a627SAlexander V. Chernikov IPFW_WLOCK(ch); 11329490a627SAlexander V. Chernikov link_table(ch, tc); 11339490a627SAlexander V. Chernikov IPFW_WUNLOCK(ch); 11349490a627SAlexander V. Chernikov 11359490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 11369490a627SAlexander V. Chernikov 11379490a627SAlexander V. Chernikov return (0); 11389490a627SAlexander V. Chernikov } 11399490a627SAlexander V. Chernikov 1140d3a4f924SAlexander V. Chernikov void 1141d3a4f924SAlexander V. Chernikov objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti) 1142d3a4f924SAlexander V. Chernikov { 1143d3a4f924SAlexander V. Chernikov 1144d3a4f924SAlexander V. Chernikov memset(ti, 0, sizeof(struct tid_info)); 114581d3153dSAlexander V. Chernikov ti->set = oh->ntlv.set; 1146d3a4f924SAlexander V. Chernikov ti->uidx = oh->idx; 1147d3a4f924SAlexander V. Chernikov ti->tlvs = &oh->ntlv; 1148d3a4f924SAlexander V. Chernikov ti->tlen = oh->ntlv.head.length; 1149d3a4f924SAlexander V. Chernikov } 1150d3a4f924SAlexander V. Chernikov 1151563b5ab1SAlexander V. Chernikov int 1152563b5ab1SAlexander V. Chernikov ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx, 1153563b5ab1SAlexander V. Chernikov struct sockopt_data *sd) 1154563b5ab1SAlexander V. Chernikov { 1155563b5ab1SAlexander V. Chernikov struct namedobj_instance *ni; 1156563b5ab1SAlexander V. Chernikov struct named_object *no; 1157563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1158563b5ab1SAlexander V. Chernikov 1159563b5ab1SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1160563b5ab1SAlexander V. Chernikov 1161ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 1162563b5ab1SAlexander V. Chernikov KASSERT(no != NULL, ("invalid table kidx passed")); 1163563b5ab1SAlexander V. Chernikov 1164563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 1165563b5ab1SAlexander V. Chernikov if (ntlv == NULL) 1166563b5ab1SAlexander V. Chernikov return (ENOMEM); 1167563b5ab1SAlexander V. Chernikov 1168563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 1169563b5ab1SAlexander V. Chernikov ntlv->head.length = sizeof(*ntlv); 1170563b5ab1SAlexander V. Chernikov ntlv->idx = no->kidx; 1171563b5ab1SAlexander V. Chernikov strlcpy(ntlv->name, no->name, sizeof(ntlv->name)); 1172563b5ab1SAlexander V. Chernikov 1173563b5ab1SAlexander V. Chernikov return (0); 1174563b5ab1SAlexander V. Chernikov } 1175563b5ab1SAlexander V. Chernikov 11769f7d47b0SAlexander V. Chernikov static void 1177ac35ff17SAlexander V. Chernikov export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 1178ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i) 11799f7d47b0SAlexander V. Chernikov { 1180ac35ff17SAlexander V. Chernikov struct table_info *ti; 11819f7d47b0SAlexander V. Chernikov 11829f7d47b0SAlexander V. Chernikov i->type = tc->no.type; 1183ac35ff17SAlexander V. Chernikov i->vtype = tc->vtype; 11849f7d47b0SAlexander V. Chernikov i->set = tc->no.set; 11859f7d47b0SAlexander V. Chernikov i->kidx = tc->no.kidx; 11869f7d47b0SAlexander V. Chernikov i->refcnt = tc->no.refcnt; 11879f7d47b0SAlexander V. Chernikov i->count = tc->count; 118881d3153dSAlexander V. Chernikov i->size = tc->count * sizeof(ipfw_obj_tentry); 1189f1220db8SAlexander V. Chernikov i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 11909f7d47b0SAlexander V. Chernikov strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); 1191ac35ff17SAlexander V. Chernikov if (tc->ta->print_config != NULL) { 1192ac35ff17SAlexander V. Chernikov /* Use algo function to print table config to string */ 1193ac35ff17SAlexander V. Chernikov ti = KIDX_TO_TI(ch, tc->no.kidx); 1194ac35ff17SAlexander V. Chernikov tc->ta->print_config(tc->astate, ti, i->algoname, 1195ac35ff17SAlexander V. Chernikov sizeof(i->algoname)); 1196ac35ff17SAlexander V. Chernikov } else 1197ac35ff17SAlexander V. Chernikov strlcpy(i->algoname, tc->ta->name, sizeof(i->algoname)); 11989f7d47b0SAlexander V. Chernikov } 11999f7d47b0SAlexander V. Chernikov 1200ac35ff17SAlexander V. Chernikov struct dump_table_args { 1201ac35ff17SAlexander V. Chernikov struct ip_fw_chain *ch; 1202ac35ff17SAlexander V. Chernikov struct sockopt_data *sd; 1203ac35ff17SAlexander V. Chernikov }; 1204ac35ff17SAlexander V. Chernikov 12059f7d47b0SAlexander V. Chernikov static void 12069f7d47b0SAlexander V. Chernikov export_table_internal(struct namedobj_instance *ni, struct named_object *no, 12079f7d47b0SAlexander V. Chernikov void *arg) 12083b3a8eb9SGleb Smirnoff { 12099f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i; 1210ac35ff17SAlexander V. Chernikov struct dump_table_args *dta; 12113b3a8eb9SGleb Smirnoff 1212ac35ff17SAlexander V. Chernikov dta = (struct dump_table_args *)arg; 1213ac35ff17SAlexander V. Chernikov 1214ac35ff17SAlexander V. Chernikov i = (ipfw_xtable_info *)ipfw_get_sopt_space(dta->sd, sizeof(*i)); 12152d99a349SAlexander V. Chernikov KASSERT(i == 0, ("previously checked buffer is not enough")); 12169f7d47b0SAlexander V. Chernikov 1217ac35ff17SAlexander V. Chernikov export_table_info(dta->ch, (struct table_config *)no, i); 12189f7d47b0SAlexander V. Chernikov } 12199f7d47b0SAlexander V. Chernikov 1220f1220db8SAlexander V. Chernikov /* 1221f1220db8SAlexander V. Chernikov * Export all tables as ipfw_xtable_info structures to 12222d99a349SAlexander V. Chernikov * storage provided by @sd. 1223f1220db8SAlexander V. Chernikov * Returns 0 on success. 1224f1220db8SAlexander V. Chernikov */ 1225f1220db8SAlexander V. Chernikov static int 12262d99a349SAlexander V. Chernikov export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 12272d99a349SAlexander V. Chernikov struct sockopt_data *sd) 12289f7d47b0SAlexander V. Chernikov { 12299f7d47b0SAlexander V. Chernikov uint32_t size; 12309f7d47b0SAlexander V. Chernikov uint32_t count; 1231ac35ff17SAlexander V. Chernikov struct dump_table_args dta; 12329f7d47b0SAlexander V. Chernikov 12339f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 12349f7d47b0SAlexander V. Chernikov size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 12352d99a349SAlexander V. Chernikov 12362d99a349SAlexander V. Chernikov /* Fill in header regadless of buffer size */ 1237f1220db8SAlexander V. Chernikov olh->count = count; 1238f1220db8SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 12392d99a349SAlexander V. Chernikov 12402d99a349SAlexander V. Chernikov if (size > olh->size) { 12412d99a349SAlexander V. Chernikov /* Store necessary size */ 12422d99a349SAlexander V. Chernikov olh->size = size; 12439f7d47b0SAlexander V. Chernikov return (ENOMEM); 1244f1220db8SAlexander V. Chernikov } 12459f7d47b0SAlexander V. Chernikov olh->size = size; 12462d99a349SAlexander V. Chernikov 1247ac35ff17SAlexander V. Chernikov dta.ch = ch; 1248ac35ff17SAlexander V. Chernikov dta.sd = sd; 1249ac35ff17SAlexander V. Chernikov 1250ac35ff17SAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, &dta); 12519f7d47b0SAlexander V. Chernikov 12523b3a8eb9SGleb Smirnoff return (0); 12533b3a8eb9SGleb Smirnoff } 12543b3a8eb9SGleb Smirnoff 125581d3153dSAlexander V. Chernikov /* 125681d3153dSAlexander V. Chernikov * Legacy IP_FW_TABLE_GETSIZE handler 125781d3153dSAlexander V. Chernikov */ 12583b3a8eb9SGleb Smirnoff int 1259b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 12603b3a8eb9SGleb Smirnoff { 1261b074b7bbSAlexander V. Chernikov struct table_config *tc; 12623b3a8eb9SGleb Smirnoff 1263b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1264b074b7bbSAlexander V. Chernikov return (ESRCH); 12659f7d47b0SAlexander V. Chernikov *cnt = tc->count; 12663b3a8eb9SGleb Smirnoff return (0); 12673b3a8eb9SGleb Smirnoff } 12683b3a8eb9SGleb Smirnoff 12699f7d47b0SAlexander V. Chernikov 127081d3153dSAlexander V. Chernikov /* 127181d3153dSAlexander V. Chernikov * Legacy IP_FW_TABLE_XGETSIZE handler 127281d3153dSAlexander V. Chernikov */ 12739f7d47b0SAlexander V. Chernikov int 12749f7d47b0SAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 12753b3a8eb9SGleb Smirnoff { 12769f7d47b0SAlexander V. Chernikov struct table_config *tc; 12779f7d47b0SAlexander V. Chernikov 1278d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) { 1279d3a4f924SAlexander V. Chernikov *cnt = 0; 12809f7d47b0SAlexander V. Chernikov return (0); /* 'table all list' requires success */ 1281d3a4f924SAlexander V. Chernikov } 12829f7d47b0SAlexander V. Chernikov *cnt = tc->count * sizeof(ipfw_table_xentry); 12839f7d47b0SAlexander V. Chernikov if (tc->count > 0) 12849f7d47b0SAlexander V. Chernikov *cnt += sizeof(ipfw_xtable); 12859f7d47b0SAlexander V. Chernikov return (0); 12869f7d47b0SAlexander V. Chernikov } 12879f7d47b0SAlexander V. Chernikov 12889f7d47b0SAlexander V. Chernikov static int 12899f7d47b0SAlexander V. Chernikov dump_table_entry(void *e, void *arg) 12909f7d47b0SAlexander V. Chernikov { 12919f7d47b0SAlexander V. Chernikov struct dump_args *da; 12929f7d47b0SAlexander V. Chernikov struct table_config *tc; 12939f7d47b0SAlexander V. Chernikov struct table_algo *ta; 12943b3a8eb9SGleb Smirnoff ipfw_table_entry *ent; 129581d3153dSAlexander V. Chernikov int error; 12963b3a8eb9SGleb Smirnoff 12979f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 12989f7d47b0SAlexander V. Chernikov 12999f7d47b0SAlexander V. Chernikov tc = da->tc; 13009f7d47b0SAlexander V. Chernikov ta = tc->ta; 13019f7d47b0SAlexander V. Chernikov 13029f7d47b0SAlexander V. Chernikov /* Out of memory, returning */ 1303f1220db8SAlexander V. Chernikov if (da->cnt == da->size) 13043b3a8eb9SGleb Smirnoff return (1); 1305f1220db8SAlexander V. Chernikov ent = da->ent++; 1306f1220db8SAlexander V. Chernikov ent->tbl = da->uidx; 1307f1220db8SAlexander V. Chernikov da->cnt++; 13089f7d47b0SAlexander V. Chernikov 130981d3153dSAlexander V. Chernikov error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent); 131081d3153dSAlexander V. Chernikov if (error != 0) 131181d3153dSAlexander V. Chernikov return (error); 131281d3153dSAlexander V. Chernikov 131381d3153dSAlexander V. Chernikov ent->addr = da->tent.k.addr.s_addr; 131481d3153dSAlexander V. Chernikov ent->masklen = da->tent.masklen; 131581d3153dSAlexander V. Chernikov ent->value = da->tent.value; 131681d3153dSAlexander V. Chernikov 131781d3153dSAlexander V. Chernikov return (0); 13183b3a8eb9SGleb Smirnoff } 13193b3a8eb9SGleb Smirnoff 1320f1220db8SAlexander V. Chernikov /* 1321f1220db8SAlexander V. Chernikov * Dumps table in pre-8.1 legacy format. 1322f1220db8SAlexander V. Chernikov */ 13233b3a8eb9SGleb Smirnoff int 1324f1220db8SAlexander V. Chernikov ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti, 1325f1220db8SAlexander V. Chernikov ipfw_table *tbl) 13263b3a8eb9SGleb Smirnoff { 1327b074b7bbSAlexander V. Chernikov struct table_config *tc; 13289f7d47b0SAlexander V. Chernikov struct table_algo *ta; 13299f7d47b0SAlexander V. Chernikov struct dump_args da; 13303b3a8eb9SGleb Smirnoff 13313b3a8eb9SGleb Smirnoff tbl->cnt = 0; 13323b3a8eb9SGleb Smirnoff 1333b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1334b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 13359f7d47b0SAlexander V. Chernikov 13369f7d47b0SAlexander V. Chernikov ta = tc->ta; 13379f7d47b0SAlexander V. Chernikov 133881d3153dSAlexander V. Chernikov /* This dump format supports IPv4 only */ 133981d3153dSAlexander V. Chernikov if (tc->no.type != IPFW_TABLE_CIDR) 134081d3153dSAlexander V. Chernikov return (0); 13419f7d47b0SAlexander V. Chernikov 1342d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 13439f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 13449f7d47b0SAlexander V. Chernikov da.tc = tc; 1345f1220db8SAlexander V. Chernikov da.ent = &tbl->ent[0]; 1346f1220db8SAlexander V. Chernikov da.size = tbl->size; 13479f7d47b0SAlexander V. Chernikov 13489f7d47b0SAlexander V. Chernikov tbl->cnt = 0; 13499f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_entry, &da); 1350f1220db8SAlexander V. Chernikov tbl->cnt = da.cnt; 13519f7d47b0SAlexander V. Chernikov 13523b3a8eb9SGleb Smirnoff return (0); 13533b3a8eb9SGleb Smirnoff } 13543b3a8eb9SGleb Smirnoff 13559490a627SAlexander V. Chernikov /* 135681d3153dSAlexander V. Chernikov * Dumps table entry in eXtended format (v1)(current). 135781d3153dSAlexander V. Chernikov */ 135881d3153dSAlexander V. Chernikov static int 135981d3153dSAlexander V. Chernikov dump_table_tentry(void *e, void *arg) 136081d3153dSAlexander V. Chernikov { 136181d3153dSAlexander V. Chernikov struct dump_args *da; 136281d3153dSAlexander V. Chernikov struct table_config *tc; 136381d3153dSAlexander V. Chernikov struct table_algo *ta; 136481d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 136581d3153dSAlexander V. Chernikov 136681d3153dSAlexander V. Chernikov da = (struct dump_args *)arg; 136781d3153dSAlexander V. Chernikov 136881d3153dSAlexander V. Chernikov tc = da->tc; 136981d3153dSAlexander V. Chernikov ta = tc->ta; 137081d3153dSAlexander V. Chernikov 137181d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent)); 137281d3153dSAlexander V. Chernikov /* Out of memory, returning */ 137381d3153dSAlexander V. Chernikov if (tent == NULL) { 137481d3153dSAlexander V. Chernikov da->error = ENOMEM; 137581d3153dSAlexander V. Chernikov return (1); 137681d3153dSAlexander V. Chernikov } 137781d3153dSAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 137881d3153dSAlexander V. Chernikov tent->idx = da->uidx; 137981d3153dSAlexander V. Chernikov 138081d3153dSAlexander V. Chernikov return (ta->dump_tentry(tc->astate, da->ti, e, tent)); 138181d3153dSAlexander V. Chernikov } 138281d3153dSAlexander V. Chernikov 138381d3153dSAlexander V. Chernikov /* 138481d3153dSAlexander V. Chernikov * Dumps table entry in eXtended format (v0). 13859490a627SAlexander V. Chernikov */ 13863b3a8eb9SGleb Smirnoff static int 13879f7d47b0SAlexander V. Chernikov dump_table_xentry(void *e, void *arg) 13883b3a8eb9SGleb Smirnoff { 13899f7d47b0SAlexander V. Chernikov struct dump_args *da; 13909f7d47b0SAlexander V. Chernikov struct table_config *tc; 13919f7d47b0SAlexander V. Chernikov struct table_algo *ta; 13923b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 139381d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 139481d3153dSAlexander V. Chernikov int error; 13953b3a8eb9SGleb Smirnoff 13969f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 13979f7d47b0SAlexander V. Chernikov 13989f7d47b0SAlexander V. Chernikov tc = da->tc; 13999f7d47b0SAlexander V. Chernikov ta = tc->ta; 14009f7d47b0SAlexander V. Chernikov 14012d99a349SAlexander V. Chernikov xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent)); 14023b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 14032d99a349SAlexander V. Chernikov if (xent == NULL) 14043b3a8eb9SGleb Smirnoff return (1); 14053b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 1406f1220db8SAlexander V. Chernikov xent->tbl = da->uidx; 14079f7d47b0SAlexander V. Chernikov 140881d3153dSAlexander V. Chernikov memset(&da->tent, 0, sizeof(da->tent)); 140981d3153dSAlexander V. Chernikov tent = &da->tent; 141081d3153dSAlexander V. Chernikov error = ta->dump_tentry(tc->astate, da->ti, e, tent); 141181d3153dSAlexander V. Chernikov if (error != 0) 141281d3153dSAlexander V. Chernikov return (error); 141381d3153dSAlexander V. Chernikov 141481d3153dSAlexander V. Chernikov /* Convert current format to previous one */ 141581d3153dSAlexander V. Chernikov xent->masklen = tent->masklen; 141681d3153dSAlexander V. Chernikov xent->value = tent->value; 141781d3153dSAlexander V. Chernikov /* Apply some hacks */ 141881d3153dSAlexander V. Chernikov if (tc->no.type == IPFW_TABLE_CIDR && tent->subtype == AF_INET) { 141981d3153dSAlexander V. Chernikov xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr; 142081d3153dSAlexander V. Chernikov xent->flags = IPFW_TCF_INET; 142181d3153dSAlexander V. Chernikov } else 142281d3153dSAlexander V. Chernikov memcpy(&xent->k, &tent->k, sizeof(xent->k)); 142381d3153dSAlexander V. Chernikov 142481d3153dSAlexander V. Chernikov return (0); 14259f7d47b0SAlexander V. Chernikov } 14269f7d47b0SAlexander V. Chernikov 14279f7d47b0SAlexander V. Chernikov /* 14289f7d47b0SAlexander V. Chernikov * Table algorithms 14299f7d47b0SAlexander V. Chernikov */ 14303b3a8eb9SGleb Smirnoff 14319f7d47b0SAlexander V. Chernikov /* 14329490a627SAlexander V. Chernikov * Finds algoritm by index, table type or supplied name 14339f7d47b0SAlexander V. Chernikov */ 14349f7d47b0SAlexander V. Chernikov static struct table_algo * 14359490a627SAlexander V. Chernikov find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name) 14369f7d47b0SAlexander V. Chernikov { 14379490a627SAlexander V. Chernikov int i, l; 14389490a627SAlexander V. Chernikov struct table_algo *ta; 14399f7d47b0SAlexander V. Chernikov 14409f7d47b0SAlexander V. Chernikov /* Search by index */ 14419f7d47b0SAlexander V. Chernikov if (ti->atype != 0) { 14429f7d47b0SAlexander V. Chernikov if (ti->atype > tcfg->algo_count) 14439f7d47b0SAlexander V. Chernikov return (NULL); 14449f7d47b0SAlexander V. Chernikov return (tcfg->algo[ti->atype]); 14459f7d47b0SAlexander V. Chernikov } 14469f7d47b0SAlexander V. Chernikov 14479490a627SAlexander V. Chernikov /* Search by name if supplied */ 14489490a627SAlexander V. Chernikov if (name != NULL) { 14499490a627SAlexander V. Chernikov /* TODO: better search */ 14509490a627SAlexander V. Chernikov for (i = 1; i <= tcfg->algo_count; i++) { 14519490a627SAlexander V. Chernikov ta = tcfg->algo[i]; 14529490a627SAlexander V. Chernikov 14539490a627SAlexander V. Chernikov /* 14549490a627SAlexander V. Chernikov * One can supply additional algorithm 14559490a627SAlexander V. Chernikov * parameters so we compare only the first word 14569490a627SAlexander V. Chernikov * of supplied name: 14579490a627SAlexander V. Chernikov * 'hash_cidr hsize=32' 14589490a627SAlexander V. Chernikov * '^^^^^^^^^' 14599490a627SAlexander V. Chernikov * 14609490a627SAlexander V. Chernikov */ 14619490a627SAlexander V. Chernikov l = strlen(ta->name); 14629490a627SAlexander V. Chernikov if (strncmp(name, ta->name, l) == 0) { 14639490a627SAlexander V. Chernikov if (name[l] == '\0' || name[l] == ' ') 14649490a627SAlexander V. Chernikov return (ta); 14659490a627SAlexander V. Chernikov } 14669490a627SAlexander V. Chernikov } 14679490a627SAlexander V. Chernikov 14689490a627SAlexander V. Chernikov return (NULL); 14699490a627SAlexander V. Chernikov } 14709490a627SAlexander V. Chernikov 14719f7d47b0SAlexander V. Chernikov /* Search by type */ 14729f7d47b0SAlexander V. Chernikov switch (ti->type) { 14733b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 14749f7d47b0SAlexander V. Chernikov return (&radix_cidr); 14753b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 14769f7d47b0SAlexander V. Chernikov return (&radix_iface); 14773b3a8eb9SGleb Smirnoff } 14783b3a8eb9SGleb Smirnoff 14799f7d47b0SAlexander V. Chernikov return (NULL); 14803b3a8eb9SGleb Smirnoff } 14813b3a8eb9SGleb Smirnoff 14829f7d47b0SAlexander V. Chernikov void 14839f7d47b0SAlexander V. Chernikov ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta) 14843b3a8eb9SGleb Smirnoff { 14859f7d47b0SAlexander V. Chernikov struct tables_config *tcfg; 14863b3a8eb9SGleb Smirnoff 14879f7d47b0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 1488b074b7bbSAlexander V. Chernikov 14899f7d47b0SAlexander V. Chernikov KASSERT(tcfg->algo_count < 255, ("Increase algo array size")); 14909f7d47b0SAlexander V. Chernikov 14919f7d47b0SAlexander V. Chernikov tcfg->algo[++tcfg->algo_count] = ta; 14929f7d47b0SAlexander V. Chernikov ta->idx = tcfg->algo_count; 14933b3a8eb9SGleb Smirnoff } 14943b3a8eb9SGleb Smirnoff 14959f7d47b0SAlexander V. Chernikov 1496b074b7bbSAlexander V. Chernikov /* 1497b074b7bbSAlexander V. Chernikov * Tables rewriting code 1498b074b7bbSAlexander V. Chernikov * 1499b074b7bbSAlexander V. Chernikov */ 1500b074b7bbSAlexander V. Chernikov 1501b074b7bbSAlexander V. Chernikov /* 1502b074b7bbSAlexander V. Chernikov * Determine table number and lookup type for @cmd. 1503b074b7bbSAlexander V. Chernikov * Fill @tbl and @type with appropriate values. 1504b074b7bbSAlexander V. Chernikov * Returns 0 for relevant opcodes, 1 otherwise. 1505b074b7bbSAlexander V. Chernikov */ 1506b074b7bbSAlexander V. Chernikov static int 1507b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 1508b074b7bbSAlexander V. Chernikov { 1509b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1510b074b7bbSAlexander V. Chernikov int skip; 1511b074b7bbSAlexander V. Chernikov uint16_t v; 1512b074b7bbSAlexander V. Chernikov 1513b074b7bbSAlexander V. Chernikov skip = 1; 1514b074b7bbSAlexander V. Chernikov 1515b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1516b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1517b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1518b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1519b074b7bbSAlexander V. Chernikov *puidx = cmd->arg1; 1520b074b7bbSAlexander V. Chernikov /* Assume CIDR by default */ 1521b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 1522b074b7bbSAlexander V. Chernikov skip = 0; 1523b074b7bbSAlexander V. Chernikov 1524b074b7bbSAlexander V. Chernikov if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { 1525b074b7bbSAlexander V. Chernikov /* 1526b074b7bbSAlexander V. Chernikov * generic lookup. The key must be 1527b074b7bbSAlexander V. Chernikov * in 32bit big-endian format. 1528b074b7bbSAlexander V. Chernikov */ 1529b074b7bbSAlexander V. Chernikov v = ((ipfw_insn_u32 *)cmd)->d[1]; 1530b074b7bbSAlexander V. Chernikov switch (v) { 1531b074b7bbSAlexander V. Chernikov case 0: 1532b074b7bbSAlexander V. Chernikov case 1: 1533b074b7bbSAlexander V. Chernikov /* IPv4 src/dst */ 1534b074b7bbSAlexander V. Chernikov break; 1535b074b7bbSAlexander V. Chernikov case 2: 1536b074b7bbSAlexander V. Chernikov case 3: 1537b074b7bbSAlexander V. Chernikov /* src/dst port */ 1538b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 1539b074b7bbSAlexander V. Chernikov break; 1540b074b7bbSAlexander V. Chernikov case 4: 1541b074b7bbSAlexander V. Chernikov /* uid/gid */ 1542b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 1543b074b7bbSAlexander V. Chernikov case 5: 1544b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 1545b074b7bbSAlexander V. Chernikov /* jid */ 1546b074b7bbSAlexander V. Chernikov case 6: 1547b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 1548b074b7bbSAlexander V. Chernikov /* dscp */ 1549b074b7bbSAlexander V. Chernikov break; 1550b074b7bbSAlexander V. Chernikov } 1551b074b7bbSAlexander V. Chernikov } 1552b074b7bbSAlexander V. Chernikov break; 1553b074b7bbSAlexander V. Chernikov case O_XMIT: 1554b074b7bbSAlexander V. Chernikov case O_RECV: 1555b074b7bbSAlexander V. Chernikov case O_VIA: 1556b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1557b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1558b074b7bbSAlexander V. Chernikov if (cmdif->name[0] != '\1') 1559b074b7bbSAlexander V. Chernikov break; 1560b074b7bbSAlexander V. Chernikov 1561b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 1562b074b7bbSAlexander V. Chernikov *puidx = cmdif->p.glob; 1563b074b7bbSAlexander V. Chernikov skip = 0; 1564b074b7bbSAlexander V. Chernikov break; 1565b074b7bbSAlexander V. Chernikov } 1566b074b7bbSAlexander V. Chernikov 1567b074b7bbSAlexander V. Chernikov return (skip); 1568b074b7bbSAlexander V. Chernikov } 1569b074b7bbSAlexander V. Chernikov 1570b074b7bbSAlexander V. Chernikov /* 1571b074b7bbSAlexander V. Chernikov * Sets new table value for given opcode. 1572b074b7bbSAlexander V. Chernikov * Assume the same opcodes as classify_table_opcode() 1573b074b7bbSAlexander V. Chernikov */ 1574b074b7bbSAlexander V. Chernikov static void 1575b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx) 1576b074b7bbSAlexander V. Chernikov { 1577b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1578b074b7bbSAlexander V. Chernikov 1579b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1580b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1581b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1582b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1583b074b7bbSAlexander V. Chernikov cmd->arg1 = idx; 1584b074b7bbSAlexander V. Chernikov break; 1585b074b7bbSAlexander V. Chernikov case O_XMIT: 1586b074b7bbSAlexander V. Chernikov case O_RECV: 1587b074b7bbSAlexander V. Chernikov case O_VIA: 1588b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1589b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1590b074b7bbSAlexander V. Chernikov cmdif->p.glob = idx; 1591b074b7bbSAlexander V. Chernikov break; 1592b074b7bbSAlexander V. Chernikov } 1593b074b7bbSAlexander V. Chernikov } 1594b074b7bbSAlexander V. Chernikov 1595ac35ff17SAlexander V. Chernikov /* 1596ac35ff17SAlexander V. Chernikov * Checks table name for validity. 1597ac35ff17SAlexander V. Chernikov * Enforce basic length checks, the rest 1598ac35ff17SAlexander V. Chernikov * should be done in userland. 1599ac35ff17SAlexander V. Chernikov * 1600ac35ff17SAlexander V. Chernikov * Returns 0 if name is considered valid. 1601ac35ff17SAlexander V. Chernikov */ 1602ac35ff17SAlexander V. Chernikov int 1603ac35ff17SAlexander V. Chernikov ipfw_check_table_name(char *name) 1604ac35ff17SAlexander V. Chernikov { 1605ac35ff17SAlexander V. Chernikov int nsize; 1606ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv = NULL; 1607ac35ff17SAlexander V. Chernikov 1608ac35ff17SAlexander V. Chernikov nsize = sizeof(ntlv->name); 1609ac35ff17SAlexander V. Chernikov 1610ac35ff17SAlexander V. Chernikov if (strnlen(name, nsize) == nsize) 1611ac35ff17SAlexander V. Chernikov return (EINVAL); 1612ac35ff17SAlexander V. Chernikov 1613ac35ff17SAlexander V. Chernikov if (name[0] == '\0') 1614ac35ff17SAlexander V. Chernikov return (EINVAL); 1615ac35ff17SAlexander V. Chernikov 1616ac35ff17SAlexander V. Chernikov /* 1617ac35ff17SAlexander V. Chernikov * TODO: do some more complicated checks 1618ac35ff17SAlexander V. Chernikov */ 1619ac35ff17SAlexander V. Chernikov 1620ac35ff17SAlexander V. Chernikov return (0); 1621ac35ff17SAlexander V. Chernikov } 1622ac35ff17SAlexander V. Chernikov 1623ac35ff17SAlexander V. Chernikov /* 1624ac35ff17SAlexander V. Chernikov * Find tablename TLV by @uid. 1625ac35ff17SAlexander V. Chernikov * Check @tlvs for valid data inside. 1626ac35ff17SAlexander V. Chernikov * 1627ac35ff17SAlexander V. Chernikov * Returns pointer to found TLV or NULL. 1628ac35ff17SAlexander V. Chernikov */ 1629ac35ff17SAlexander V. Chernikov static ipfw_obj_ntlv * 1630b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx) 1631b074b7bbSAlexander V. Chernikov { 16329f7d47b0SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1633b074b7bbSAlexander V. Chernikov uintptr_t pa, pe; 1634b074b7bbSAlexander V. Chernikov int l; 1635b074b7bbSAlexander V. Chernikov 1636b074b7bbSAlexander V. Chernikov pa = (uintptr_t)tlvs; 1637b074b7bbSAlexander V. Chernikov pe = pa + len; 1638b074b7bbSAlexander V. Chernikov l = 0; 1639b074b7bbSAlexander V. Chernikov for (; pa < pe; pa += l) { 16409f7d47b0SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)pa; 1641b074b7bbSAlexander V. Chernikov l = ntlv->head.length; 1642ac35ff17SAlexander V. Chernikov 1643ac35ff17SAlexander V. Chernikov if (l != sizeof(*ntlv)) 1644ac35ff17SAlexander V. Chernikov return (NULL); 1645ac35ff17SAlexander V. Chernikov 1646563b5ab1SAlexander V. Chernikov if (ntlv->head.type != IPFW_TLV_TBL_NAME) 1647b074b7bbSAlexander V. Chernikov continue; 1648ac35ff17SAlexander V. Chernikov 1649b074b7bbSAlexander V. Chernikov if (ntlv->idx != uidx) 1650b074b7bbSAlexander V. Chernikov continue; 1651b074b7bbSAlexander V. Chernikov 1652ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(ntlv->name) != 0) 1653ac35ff17SAlexander V. Chernikov return (NULL); 1654ac35ff17SAlexander V. Chernikov 1655ac35ff17SAlexander V. Chernikov return (ntlv); 1656b074b7bbSAlexander V. Chernikov } 1657b074b7bbSAlexander V. Chernikov 1658b074b7bbSAlexander V. Chernikov return (NULL); 1659b074b7bbSAlexander V. Chernikov } 1660b074b7bbSAlexander V. Chernikov 1661ac35ff17SAlexander V. Chernikov /* 1662ac35ff17SAlexander V. Chernikov * Finds table config based on either legacy index 1663ac35ff17SAlexander V. Chernikov * or name in ntlv. 1664ac35ff17SAlexander V. Chernikov * Note @ti structure contains unchecked data from userland. 1665ac35ff17SAlexander V. Chernikov * 1666ac35ff17SAlexander V. Chernikov * Returns pointer to table_config or NULL. 1667ac35ff17SAlexander V. Chernikov */ 1668b074b7bbSAlexander V. Chernikov static struct table_config * 1669b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti) 1670b074b7bbSAlexander V. Chernikov { 1671b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1672b074b7bbSAlexander V. Chernikov struct named_object *no; 1673ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1674ac35ff17SAlexander V. Chernikov uint32_t set; 1675b074b7bbSAlexander V. Chernikov 1676b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1677ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1678ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1679b074b7bbSAlexander V. Chernikov return (NULL); 1680ac35ff17SAlexander V. Chernikov name = ntlv->name; 1681ac35ff17SAlexander V. Chernikov set = ntlv->set; 1682b074b7bbSAlexander V. Chernikov } else { 1683b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1684b074b7bbSAlexander V. Chernikov name = bname; 1685ac35ff17SAlexander V. Chernikov set = 0; 1686b074b7bbSAlexander V. Chernikov } 1687b074b7bbSAlexander V. Chernikov 1688ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_name(ni, set, name); 1689b074b7bbSAlexander V. Chernikov 1690b074b7bbSAlexander V. Chernikov return ((struct table_config *)no); 1691b074b7bbSAlexander V. Chernikov } 1692b074b7bbSAlexander V. Chernikov 1693b074b7bbSAlexander V. Chernikov static struct table_config * 16949f7d47b0SAlexander V. Chernikov alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti, 16959490a627SAlexander V. Chernikov struct table_algo *ta, char *aname) 1696b074b7bbSAlexander V. Chernikov { 1697b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1698b074b7bbSAlexander V. Chernikov struct table_config *tc; 1699b074b7bbSAlexander V. Chernikov int error; 1700ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1701ac35ff17SAlexander V. Chernikov uint32_t set; 1702b074b7bbSAlexander V. Chernikov 1703b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1704ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1705ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1706b074b7bbSAlexander V. Chernikov return (NULL); 1707ac35ff17SAlexander V. Chernikov name = ntlv->name; 1708ac35ff17SAlexander V. Chernikov set = ntlv->set; 1709b074b7bbSAlexander V. Chernikov } else { 1710b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1711b074b7bbSAlexander V. Chernikov name = bname; 1712ac35ff17SAlexander V. Chernikov set = 0; 1713b074b7bbSAlexander V. Chernikov } 1714b074b7bbSAlexander V. Chernikov 1715b074b7bbSAlexander V. Chernikov tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO); 1716b074b7bbSAlexander V. Chernikov tc->no.name = tc->tablename; 1717b074b7bbSAlexander V. Chernikov tc->no.type = ti->type; 1718ac35ff17SAlexander V. Chernikov tc->no.set = set; 17199f7d47b0SAlexander V. Chernikov tc->ta = ta; 1720b074b7bbSAlexander V. Chernikov strlcpy(tc->tablename, name, sizeof(tc->tablename)); 1721ac35ff17SAlexander V. Chernikov /* Set default value type to u32 for compability reasons */ 1722ac35ff17SAlexander V. Chernikov tc->vtype = IPFW_VTYPE_U32; 1723b074b7bbSAlexander V. Chernikov 1724b074b7bbSAlexander V. Chernikov if (ti->tlvs == NULL) { 1725b074b7bbSAlexander V. Chernikov tc->no.compat = 1; 1726b074b7bbSAlexander V. Chernikov tc->no.uidx = ti->uidx; 1727b074b7bbSAlexander V. Chernikov } 1728b074b7bbSAlexander V. Chernikov 1729b074b7bbSAlexander V. Chernikov /* Preallocate data structures for new tables */ 17309490a627SAlexander V. Chernikov error = ta->init(&tc->astate, &tc->ti, aname); 1731b074b7bbSAlexander V. Chernikov if (error != 0) { 1732b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1733b074b7bbSAlexander V. Chernikov return (NULL); 1734b074b7bbSAlexander V. Chernikov } 1735b074b7bbSAlexander V. Chernikov 1736b074b7bbSAlexander V. Chernikov return (tc); 1737b074b7bbSAlexander V. Chernikov } 1738b074b7bbSAlexander V. Chernikov 1739b074b7bbSAlexander V. Chernikov static void 1740b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc) 1741b074b7bbSAlexander V. Chernikov { 1742b074b7bbSAlexander V. Chernikov 1743b074b7bbSAlexander V. Chernikov if (tc->linked == 0) 17449f7d47b0SAlexander V. Chernikov tc->ta->destroy(&tc->astate, &tc->ti); 1745b074b7bbSAlexander V. Chernikov 1746b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1747b074b7bbSAlexander V. Chernikov } 1748b074b7bbSAlexander V. Chernikov 1749b074b7bbSAlexander V. Chernikov /* 1750b074b7bbSAlexander V. Chernikov * Links @tc to @chain table named instance. 1751b074b7bbSAlexander V. Chernikov * Sets appropriate type/states in @chain table info. 1752b074b7bbSAlexander V. Chernikov */ 1753b074b7bbSAlexander V. Chernikov static void 17549f7d47b0SAlexander V. Chernikov link_table(struct ip_fw_chain *ch, struct table_config *tc) 1755b074b7bbSAlexander V. Chernikov { 1756b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 17579f7d47b0SAlexander V. Chernikov struct table_info *ti; 1758b074b7bbSAlexander V. Chernikov uint16_t kidx; 1759b074b7bbSAlexander V. Chernikov 17609f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 17619f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1762b074b7bbSAlexander V. Chernikov 17639f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1764b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1765b074b7bbSAlexander V. Chernikov 1766b074b7bbSAlexander V. Chernikov ipfw_objhash_add(ni, &tc->no); 17679f7d47b0SAlexander V. Chernikov 17689f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 17699f7d47b0SAlexander V. Chernikov *ti = tc->ti; 1770b074b7bbSAlexander V. Chernikov 1771b074b7bbSAlexander V. Chernikov tc->linked = 1; 1772b074b7bbSAlexander V. Chernikov } 1773b074b7bbSAlexander V. Chernikov 1774b074b7bbSAlexander V. Chernikov /* 1775b074b7bbSAlexander V. Chernikov * Unlinks @tc from @chain table named instance. 1776b074b7bbSAlexander V. Chernikov * Zeroes states in @chain and stores them in @tc. 1777b074b7bbSAlexander V. Chernikov */ 1778b074b7bbSAlexander V. Chernikov static void 17799f7d47b0SAlexander V. Chernikov unlink_table(struct ip_fw_chain *ch, struct table_config *tc) 1780b074b7bbSAlexander V. Chernikov { 1781b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 17829f7d47b0SAlexander V. Chernikov struct table_info *ti; 1783b074b7bbSAlexander V. Chernikov uint16_t kidx; 1784b074b7bbSAlexander V. Chernikov 17859f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 17869f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 1787b074b7bbSAlexander V. Chernikov 17889f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1789b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1790b074b7bbSAlexander V. Chernikov 17919f7d47b0SAlexander V. Chernikov /* Clear state. @ti copy is already saved inside @tc */ 1792b074b7bbSAlexander V. Chernikov ipfw_objhash_del(ni, &tc->no); 17939f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 17949f7d47b0SAlexander V. Chernikov memset(ti, 0, sizeof(struct table_info)); 1795b074b7bbSAlexander V. Chernikov tc->linked = 0; 1796b074b7bbSAlexander V. Chernikov } 1797b074b7bbSAlexander V. Chernikov 1798b074b7bbSAlexander V. Chernikov /* 1799b074b7bbSAlexander V. Chernikov * Finds named object by @uidx number. 1800b074b7bbSAlexander V. Chernikov * Refs found object, allocate new index for non-existing object. 18019490a627SAlexander V. Chernikov * Fills in @oib with userland/kernel indexes. 18029490a627SAlexander V. Chernikov * First free oidx pointer is saved back in @oib. 1803b074b7bbSAlexander V. Chernikov * 1804b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1805b074b7bbSAlexander V. Chernikov */ 1806b074b7bbSAlexander V. Chernikov static int 18079490a627SAlexander V. Chernikov bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule, 18089490a627SAlexander V. Chernikov struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti) 1809b074b7bbSAlexander V. Chernikov { 1810b074b7bbSAlexander V. Chernikov struct table_config *tc; 18119490a627SAlexander V. Chernikov struct namedobj_instance *ni; 18129490a627SAlexander V. Chernikov struct named_object *no; 18139490a627SAlexander V. Chernikov int error, l, cmdlen; 18149490a627SAlexander V. Chernikov ipfw_insn *cmd; 18159490a627SAlexander V. Chernikov struct obj_idx *pidx, *p; 18169490a627SAlexander V. Chernikov 18179490a627SAlexander V. Chernikov pidx = *oib; 18189490a627SAlexander V. Chernikov l = rule->cmd_len; 18199490a627SAlexander V. Chernikov cmd = rule->cmd; 18209490a627SAlexander V. Chernikov cmdlen = 0; 18219490a627SAlexander V. Chernikov error = 0; 18229490a627SAlexander V. Chernikov 18239490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 18249490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 18259490a627SAlexander V. Chernikov 18269490a627SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 18279490a627SAlexander V. Chernikov cmdlen = F_LEN(cmd); 18289490a627SAlexander V. Chernikov 18299490a627SAlexander V. Chernikov if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0) 18309490a627SAlexander V. Chernikov continue; 1831b074b7bbSAlexander V. Chernikov 1832b074b7bbSAlexander V. Chernikov pidx->uidx = ti->uidx; 1833b074b7bbSAlexander V. Chernikov pidx->type = ti->type; 1834b074b7bbSAlexander V. Chernikov 18359490a627SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 18369490a627SAlexander V. Chernikov if (tc->no.type != ti->type) { 18379490a627SAlexander V. Chernikov /* Incompatible types */ 18389490a627SAlexander V. Chernikov error = EINVAL; 18399490a627SAlexander V. Chernikov break; 18409490a627SAlexander V. Chernikov } 18419f7d47b0SAlexander V. Chernikov 18429490a627SAlexander V. Chernikov /* Reference found table and save kidx */ 18439490a627SAlexander V. Chernikov tc->no.refcnt++; 18449490a627SAlexander V. Chernikov pidx->kidx = tc->no.kidx; 18459490a627SAlexander V. Chernikov pidx++; 18469490a627SAlexander V. Chernikov continue; 18479490a627SAlexander V. Chernikov } 18489490a627SAlexander V. Chernikov 18499490a627SAlexander V. Chernikov /* Table not found. Allocate new index and save for later */ 1850ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &pidx->kidx) != 0) { 1851ac35ff17SAlexander V. Chernikov printf("Unable to allocate table %s index in set %u." 1852b074b7bbSAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 1853ac35ff17SAlexander V. Chernikov "", ti->set); 18549490a627SAlexander V. Chernikov error = EBUSY; 18559490a627SAlexander V. Chernikov break; 1856b074b7bbSAlexander V. Chernikov } 1857b074b7bbSAlexander V. Chernikov 1858b074b7bbSAlexander V. Chernikov ci->new_tables++; 18599490a627SAlexander V. Chernikov pidx->new = 1; 18609490a627SAlexander V. Chernikov pidx++; 1861b074b7bbSAlexander V. Chernikov } 1862b074b7bbSAlexander V. Chernikov 18639490a627SAlexander V. Chernikov if (error != 0) { 18649490a627SAlexander V. Chernikov /* Unref everything we have already done */ 18659490a627SAlexander V. Chernikov for (p = *oib; p < pidx; p++) { 18669490a627SAlexander V. Chernikov if (p->new != 0) { 1867ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, p->kidx); 18689490a627SAlexander V. Chernikov continue; 18699490a627SAlexander V. Chernikov } 1870b074b7bbSAlexander V. Chernikov 18719490a627SAlexander V. Chernikov /* Find & unref by existing idx */ 1872ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, p->kidx); 18739490a627SAlexander V. Chernikov KASSERT(no != NULL, ("Ref'd table %d disappeared", 18749490a627SAlexander V. Chernikov p->kidx)); 1875b074b7bbSAlexander V. Chernikov 18769490a627SAlexander V. Chernikov no->refcnt--; 18779490a627SAlexander V. Chernikov } 18789490a627SAlexander V. Chernikov } 18799490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1880b074b7bbSAlexander V. Chernikov 18819490a627SAlexander V. Chernikov *oib = pidx; 18829490a627SAlexander V. Chernikov 18839490a627SAlexander V. Chernikov return (error); 1884b074b7bbSAlexander V. Chernikov } 1885b074b7bbSAlexander V. Chernikov 1886b074b7bbSAlexander V. Chernikov /* 1887b074b7bbSAlexander V. Chernikov * Compatibility function for old ipfw(8) binaries. 1888b074b7bbSAlexander V. Chernikov * Rewrites table kernel indices with userland ones. 1889b074b7bbSAlexander V. Chernikov * Works for \d+ talbes only (e.g. for tables, converted 1890b074b7bbSAlexander V. Chernikov * from old numbered system calls). 1891b074b7bbSAlexander V. Chernikov * 1892b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1893b074b7bbSAlexander V. Chernikov * Raises error on any other tables. 1894b074b7bbSAlexander V. Chernikov */ 1895b074b7bbSAlexander V. Chernikov int 1896b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule) 1897b074b7bbSAlexander V. Chernikov { 18981832a7b3SAlexander V. Chernikov int cmdlen, error, l; 1899b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 19001832a7b3SAlexander V. Chernikov uint16_t kidx, uidx; 1901b074b7bbSAlexander V. Chernikov uint8_t type; 1902b074b7bbSAlexander V. Chernikov struct named_object *no; 1903b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1904b074b7bbSAlexander V. Chernikov 1905b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 19061832a7b3SAlexander V. Chernikov error = 0; 1907b074b7bbSAlexander V. Chernikov 1908b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1909b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1910b074b7bbSAlexander V. Chernikov cmdlen = 0; 1911b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1912b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1913b074b7bbSAlexander V. Chernikov 1914b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1915b074b7bbSAlexander V. Chernikov continue; 1916b074b7bbSAlexander V. Chernikov 1917ac35ff17SAlexander V. Chernikov if ((no = ipfw_objhash_lookup_kidx(ni, kidx)) == NULL) 1918b074b7bbSAlexander V. Chernikov return (1); 1919b074b7bbSAlexander V. Chernikov 19201832a7b3SAlexander V. Chernikov uidx = no->uidx; 19211832a7b3SAlexander V. Chernikov if (no->compat == 0) { 1922b074b7bbSAlexander V. Chernikov 19231832a7b3SAlexander V. Chernikov /* 19241832a7b3SAlexander V. Chernikov * We are called via legacy opcode. 19251832a7b3SAlexander V. Chernikov * Save error and show table as fake number 19261832a7b3SAlexander V. Chernikov * not to make ipfw(8) hang. 19271832a7b3SAlexander V. Chernikov */ 19281832a7b3SAlexander V. Chernikov uidx = 65535; 19291832a7b3SAlexander V. Chernikov error = 2; 1930b074b7bbSAlexander V. Chernikov } 1931b074b7bbSAlexander V. Chernikov 19321832a7b3SAlexander V. Chernikov update_table_opcode(cmd, uidx); 19331832a7b3SAlexander V. Chernikov } 19341832a7b3SAlexander V. Chernikov 19351832a7b3SAlexander V. Chernikov return (error); 1936b074b7bbSAlexander V. Chernikov } 1937b074b7bbSAlexander V. Chernikov 1938563b5ab1SAlexander V. Chernikov /* 1939563b5ab1SAlexander V. Chernikov * Sets every table kidx in @bmask which is used in rule @rule. 1940563b5ab1SAlexander V. Chernikov * 1941563b5ab1SAlexander V. Chernikov * Returns number of newly-referenced tables. 1942563b5ab1SAlexander V. Chernikov */ 1943563b5ab1SAlexander V. Chernikov int 1944563b5ab1SAlexander V. Chernikov ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule, 1945563b5ab1SAlexander V. Chernikov uint32_t *bmask) 1946563b5ab1SAlexander V. Chernikov { 1947563b5ab1SAlexander V. Chernikov int cmdlen, l, count; 1948563b5ab1SAlexander V. Chernikov ipfw_insn *cmd; 1949563b5ab1SAlexander V. Chernikov uint16_t kidx; 1950563b5ab1SAlexander V. Chernikov uint8_t type; 1951563b5ab1SAlexander V. Chernikov 1952563b5ab1SAlexander V. Chernikov l = rule->cmd_len; 1953563b5ab1SAlexander V. Chernikov cmd = rule->cmd; 1954563b5ab1SAlexander V. Chernikov cmdlen = 0; 1955563b5ab1SAlexander V. Chernikov count = 0; 1956563b5ab1SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1957563b5ab1SAlexander V. Chernikov cmdlen = F_LEN(cmd); 1958563b5ab1SAlexander V. Chernikov 1959563b5ab1SAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1960563b5ab1SAlexander V. Chernikov continue; 1961563b5ab1SAlexander V. Chernikov 1962563b5ab1SAlexander V. Chernikov if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0) 1963563b5ab1SAlexander V. Chernikov count++; 1964563b5ab1SAlexander V. Chernikov 1965563b5ab1SAlexander V. Chernikov bmask[kidx / 32] |= 1 << (kidx % 32); 1966563b5ab1SAlexander V. Chernikov } 1967563b5ab1SAlexander V. Chernikov 1968563b5ab1SAlexander V. Chernikov return (count); 1969563b5ab1SAlexander V. Chernikov } 1970563b5ab1SAlexander V. Chernikov 1971563b5ab1SAlexander V. Chernikov 1972b074b7bbSAlexander V. Chernikov 1973b074b7bbSAlexander V. Chernikov /* 1974b074b7bbSAlexander V. Chernikov * Checks is opcode is referencing table of appropriate type. 1975b074b7bbSAlexander V. Chernikov * Adds reference count for found table if true. 1976b074b7bbSAlexander V. Chernikov * Rewrites user-supplied opcode values with kernel ones. 1977b074b7bbSAlexander V. Chernikov * 1978b074b7bbSAlexander V. Chernikov * Returns 0 on success and appropriate error code otherwise. 1979b074b7bbSAlexander V. Chernikov */ 1980b074b7bbSAlexander V. Chernikov int 1981b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, 1982b074b7bbSAlexander V. Chernikov struct rule_check_info *ci) 1983b074b7bbSAlexander V. Chernikov { 1984b074b7bbSAlexander V. Chernikov int cmdlen, error, ftype, l; 1985b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1986b074b7bbSAlexander V. Chernikov uint16_t uidx; 1987b074b7bbSAlexander V. Chernikov uint8_t type; 1988b074b7bbSAlexander V. Chernikov struct table_config *tc; 19899f7d47b0SAlexander V. Chernikov struct table_algo *ta; 1990b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1991b074b7bbSAlexander V. Chernikov struct named_object *no, *no_n, *no_tmp; 19929490a627SAlexander V. Chernikov struct obj_idx *p, *pidx_first, *pidx_last; 1993b074b7bbSAlexander V. Chernikov struct namedobjects_head nh; 1994b074b7bbSAlexander V. Chernikov struct tid_info ti; 1995b074b7bbSAlexander V. Chernikov 1996b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1997b074b7bbSAlexander V. Chernikov 19989490a627SAlexander V. Chernikov /* Prepare queue to store configs */ 19999490a627SAlexander V. Chernikov TAILQ_INIT(&nh); 20009490a627SAlexander V. Chernikov 2001b074b7bbSAlexander V. Chernikov /* 2002b074b7bbSAlexander V. Chernikov * Prepare an array for storing opcode indices. 2003b074b7bbSAlexander V. Chernikov * Use stack allocation by default. 2004b074b7bbSAlexander V. Chernikov */ 2005b074b7bbSAlexander V. Chernikov if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 2006b074b7bbSAlexander V. Chernikov /* Stack */ 20079490a627SAlexander V. Chernikov pidx_first = ci->obuf; 2008b074b7bbSAlexander V. Chernikov } else 20099490a627SAlexander V. Chernikov pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx), 2010b074b7bbSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 2011b074b7bbSAlexander V. Chernikov 20129490a627SAlexander V. Chernikov pidx_last = pidx_first; 2013b074b7bbSAlexander V. Chernikov error = 0; 2014b074b7bbSAlexander V. Chernikov 2015b074b7bbSAlexander V. Chernikov type = 0; 2016b074b7bbSAlexander V. Chernikov ftype = 0; 2017b074b7bbSAlexander V. Chernikov 2018b074b7bbSAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 20191832a7b3SAlexander V. Chernikov 20201832a7b3SAlexander V. Chernikov /* 20211832a7b3SAlexander V. Chernikov * Use default set for looking up tables (old way) or 20221832a7b3SAlexander V. Chernikov * use set rule is assigned to (new way). 20231832a7b3SAlexander V. Chernikov */ 20241832a7b3SAlexander V. Chernikov ti.set = (V_fw_tables_sets != 0) ? ci->krule->set : 0; 20256c2997ffSAlexander V. Chernikov if (ci->ctlv != NULL) { 20266c2997ffSAlexander V. Chernikov ti.tlvs = (void *)(ci->ctlv + 1); 20276c2997ffSAlexander V. Chernikov ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv); 20286c2997ffSAlexander V. Chernikov } 2029b074b7bbSAlexander V. Chernikov 2030b074b7bbSAlexander V. Chernikov /* 20319490a627SAlexander V. Chernikov * Stage 1: reference existing tables, determine number 20329490a627SAlexander V. Chernikov * of tables we need to allocate and allocate indexes for each. 2033b074b7bbSAlexander V. Chernikov */ 20349490a627SAlexander V. Chernikov error = bind_table_rule(chain, ci->krule, ci, &pidx_last, &ti); 2035b074b7bbSAlexander V. Chernikov 2036b074b7bbSAlexander V. Chernikov if (error != 0) { 20379490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 20389490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 2039b074b7bbSAlexander V. Chernikov 2040b074b7bbSAlexander V. Chernikov return (error); 2041b074b7bbSAlexander V. Chernikov } 2042b074b7bbSAlexander V. Chernikov 2043b074b7bbSAlexander V. Chernikov /* 2044b074b7bbSAlexander V. Chernikov * Stage 2: allocate table configs for every non-existent table 2045b074b7bbSAlexander V. Chernikov */ 2046b074b7bbSAlexander V. Chernikov 20479f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 20489490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 2049b074b7bbSAlexander V. Chernikov if (p->new == 0) 2050b074b7bbSAlexander V. Chernikov continue; 2051b074b7bbSAlexander V. Chernikov 2052b074b7bbSAlexander V. Chernikov ti.uidx = p->uidx; 2053b074b7bbSAlexander V. Chernikov ti.type = p->type; 20549f7d47b0SAlexander V. Chernikov ti.atype = 0; 2055b074b7bbSAlexander V. Chernikov 20569490a627SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti, NULL); 20579f7d47b0SAlexander V. Chernikov if (ta == NULL) { 20589f7d47b0SAlexander V. Chernikov error = ENOTSUP; 20599f7d47b0SAlexander V. Chernikov goto free; 20609f7d47b0SAlexander V. Chernikov } 20619490a627SAlexander V. Chernikov tc = alloc_table_config(ni, &ti, ta, NULL); 2062b074b7bbSAlexander V. Chernikov 2063b074b7bbSAlexander V. Chernikov if (tc == NULL) { 2064b074b7bbSAlexander V. Chernikov error = ENOMEM; 2065b074b7bbSAlexander V. Chernikov goto free; 2066b074b7bbSAlexander V. Chernikov } 2067b074b7bbSAlexander V. Chernikov 2068b074b7bbSAlexander V. Chernikov tc->no.kidx = p->kidx; 2069b074b7bbSAlexander V. Chernikov tc->no.refcnt = 1; 2070b074b7bbSAlexander V. Chernikov 2071b074b7bbSAlexander V. Chernikov /* Add to list */ 2072b074b7bbSAlexander V. Chernikov TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next); 2073b074b7bbSAlexander V. Chernikov } 2074b074b7bbSAlexander V. Chernikov 2075b074b7bbSAlexander V. Chernikov /* 2076b074b7bbSAlexander V. Chernikov * Stage 2.1: Check if we're going to create 2 tables 2077b074b7bbSAlexander V. Chernikov * with the same name, but different table types. 2078b074b7bbSAlexander V. Chernikov */ 2079b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no, &nh, nn_next) { 2080b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no_tmp, &nh, nn_next) { 20819490a627SAlexander V. Chernikov if (ipfw_objhash_same_name(ni, no, no_tmp) == 0) 2082b074b7bbSAlexander V. Chernikov continue; 2083b074b7bbSAlexander V. Chernikov if (no->type != no_tmp->type) { 2084b074b7bbSAlexander V. Chernikov error = EINVAL; 2085b074b7bbSAlexander V. Chernikov goto free; 2086b074b7bbSAlexander V. Chernikov } 2087b074b7bbSAlexander V. Chernikov } 2088b074b7bbSAlexander V. Chernikov } 20899f7d47b0SAlexander V. Chernikov } 2090b074b7bbSAlexander V. Chernikov 20919f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 20929f7d47b0SAlexander V. Chernikov 20939f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 2094b074b7bbSAlexander V. Chernikov /* 2095b074b7bbSAlexander V. Chernikov * Stage 3: link & reference new table configs 2096b074b7bbSAlexander V. Chernikov */ 2097b074b7bbSAlexander V. Chernikov 2098b074b7bbSAlexander V. Chernikov 2099b074b7bbSAlexander V. Chernikov /* 2100b074b7bbSAlexander V. Chernikov * Step 3.1: Check if some tables we need to create have been 2101b074b7bbSAlexander V. Chernikov * already created with different table type. 2102b074b7bbSAlexander V. Chernikov */ 2103b074b7bbSAlexander V. Chernikov 2104b074b7bbSAlexander V. Chernikov error = 0; 2105b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2106b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 2107b074b7bbSAlexander V. Chernikov if (no_n == NULL) 2108b074b7bbSAlexander V. Chernikov continue; 2109b074b7bbSAlexander V. Chernikov 2110b074b7bbSAlexander V. Chernikov if (no_n->type != no->type) { 2111b074b7bbSAlexander V. Chernikov error = EINVAL; 2112b074b7bbSAlexander V. Chernikov break; 2113b074b7bbSAlexander V. Chernikov } 2114b074b7bbSAlexander V. Chernikov 2115b074b7bbSAlexander V. Chernikov } 2116b074b7bbSAlexander V. Chernikov 2117b074b7bbSAlexander V. Chernikov if (error != 0) { 2118b074b7bbSAlexander V. Chernikov /* 2119b074b7bbSAlexander V. Chernikov * Someone has allocated table with different table type. 2120b074b7bbSAlexander V. Chernikov * We have to rollback everything. 2121b074b7bbSAlexander V. Chernikov */ 2122b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 2123b074b7bbSAlexander V. Chernikov goto free; 2124b074b7bbSAlexander V. Chernikov } 2125b074b7bbSAlexander V. Chernikov 2126b074b7bbSAlexander V. Chernikov /* 21279f7d47b0SAlexander V. Chernikov * Attach new tables. 21289f7d47b0SAlexander V. Chernikov * We need to set table pointers for each new table, 2129b074b7bbSAlexander V. Chernikov * so we have to acquire main WLOCK. 2130b074b7bbSAlexander V. Chernikov */ 2131b074b7bbSAlexander V. Chernikov IPFW_WLOCK(chain); 2132b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2133b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 2134b074b7bbSAlexander V. Chernikov 21359490a627SAlexander V. Chernikov if (no_n == NULL) { 21369490a627SAlexander V. Chernikov /* New table. Attach to runtime hash */ 21379490a627SAlexander V. Chernikov TAILQ_REMOVE(&nh, no, nn_next); 21389490a627SAlexander V. Chernikov link_table(chain, (struct table_config *)no); 2139b074b7bbSAlexander V. Chernikov continue; 2140b074b7bbSAlexander V. Chernikov } 2141b074b7bbSAlexander V. Chernikov 21429490a627SAlexander V. Chernikov /* 21439490a627SAlexander V. Chernikov * Newly-allocated table with the same type. 21449490a627SAlexander V. Chernikov * Reference it and update out @pidx array 21459490a627SAlexander V. Chernikov * rewrite info. 21469490a627SAlexander V. Chernikov */ 21479490a627SAlexander V. Chernikov no_n->refcnt++; 21489490a627SAlexander V. Chernikov /* Keep oib array in sync: update kidx */ 21499490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 21509490a627SAlexander V. Chernikov if (p->kidx != no->kidx) 21519490a627SAlexander V. Chernikov continue; 21529490a627SAlexander V. Chernikov /* Update kidx */ 21539490a627SAlexander V. Chernikov p->kidx = no_n->kidx; 21549490a627SAlexander V. Chernikov break; 21559490a627SAlexander V. Chernikov } 2156b074b7bbSAlexander V. Chernikov } 2157b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(chain); 21589f7d47b0SAlexander V. Chernikov } 2159b074b7bbSAlexander V. Chernikov 2160b074b7bbSAlexander V. Chernikov /* Perform rule rewrite */ 2161b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 2162b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 2163b074b7bbSAlexander V. Chernikov cmdlen = 0; 21649490a627SAlexander V. Chernikov p = pidx_first; 2165b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2166b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2167b074b7bbSAlexander V. Chernikov 2168b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &uidx, &type) != 0) 2169b074b7bbSAlexander V. Chernikov continue; 21709490a627SAlexander V. Chernikov update_table_opcode(cmd, p->kidx); 21719490a627SAlexander V. Chernikov p++; 2172b074b7bbSAlexander V. Chernikov } 2173b074b7bbSAlexander V. Chernikov 2174b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 2175b074b7bbSAlexander V. Chernikov 2176b074b7bbSAlexander V. Chernikov error = 0; 2177b074b7bbSAlexander V. Chernikov 2178b074b7bbSAlexander V. Chernikov /* 2179b074b7bbSAlexander V. Chernikov * Stage 4: free resources 2180b074b7bbSAlexander V. Chernikov */ 2181b074b7bbSAlexander V. Chernikov free: 21829490a627SAlexander V. Chernikov if (!TAILQ_EMPTY(&nh)) { 21839490a627SAlexander V. Chernikov /* Free indexes first */ 21849490a627SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 21859490a627SAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2186ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, no->kidx); 21879490a627SAlexander V. Chernikov } 21889490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 21899490a627SAlexander V. Chernikov /* Free configs */ 2190b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) 2191b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 21929490a627SAlexander V. Chernikov } 2193b074b7bbSAlexander V. Chernikov 21949490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 21959490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 2196b074b7bbSAlexander V. Chernikov 2197b074b7bbSAlexander V. Chernikov return (error); 2198b074b7bbSAlexander V. Chernikov } 2199b074b7bbSAlexander V. Chernikov 2200b074b7bbSAlexander V. Chernikov /* 2201b074b7bbSAlexander V. Chernikov * Remove references from every table used in @rule. 2202b074b7bbSAlexander V. Chernikov */ 2203b074b7bbSAlexander V. Chernikov void 2204b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule) 2205b074b7bbSAlexander V. Chernikov { 2206b074b7bbSAlexander V. Chernikov int cmdlen, l; 2207b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 2208b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2209b074b7bbSAlexander V. Chernikov struct named_object *no; 2210b074b7bbSAlexander V. Chernikov uint16_t kidx; 2211b074b7bbSAlexander V. Chernikov uint8_t type; 2212b074b7bbSAlexander V. Chernikov 2213b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 2214b074b7bbSAlexander V. Chernikov 2215b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 2216b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 2217b074b7bbSAlexander V. Chernikov cmdlen = 0; 2218b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2219b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2220b074b7bbSAlexander V. Chernikov 2221b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2222b074b7bbSAlexander V. Chernikov continue; 2223b074b7bbSAlexander V. Chernikov 2224ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 2225b074b7bbSAlexander V. Chernikov 2226b074b7bbSAlexander V. Chernikov KASSERT(no != NULL, ("table id %d not found", kidx)); 2227b074b7bbSAlexander V. Chernikov KASSERT(no->type == type, ("wrong type %d (%d) for table id %d", 2228b074b7bbSAlexander V. Chernikov no->type, type, kidx)); 2229b074b7bbSAlexander V. Chernikov KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 2230b074b7bbSAlexander V. Chernikov kidx, no->refcnt)); 2231b074b7bbSAlexander V. Chernikov 2232b074b7bbSAlexander V. Chernikov no->refcnt--; 2233b074b7bbSAlexander V. Chernikov } 2234b074b7bbSAlexander V. Chernikov } 2235b074b7bbSAlexander V. Chernikov 2236b074b7bbSAlexander V. Chernikov 2237b074b7bbSAlexander V. Chernikov /* 2238b074b7bbSAlexander V. Chernikov * Removes table bindings for every rule in rule chain @head. 2239b074b7bbSAlexander V. Chernikov */ 2240b074b7bbSAlexander V. Chernikov void 2241b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head) 2242b074b7bbSAlexander V. Chernikov { 2243b074b7bbSAlexander V. Chernikov struct ip_fw *rule; 2244b074b7bbSAlexander V. Chernikov 2245b074b7bbSAlexander V. Chernikov while ((rule = head) != NULL) { 2246b074b7bbSAlexander V. Chernikov head = head->x_next; 2247b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(chain, rule); 2248b074b7bbSAlexander V. Chernikov } 2249b074b7bbSAlexander V. Chernikov } 2250b074b7bbSAlexander V. Chernikov 2251b074b7bbSAlexander V. Chernikov 22523b3a8eb9SGleb Smirnoff /* end of file */ 2253