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 543b3a8eb9SGleb Smirnoff #include <netinet/in.h> 553b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 563b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h> 573b3a8eb9SGleb Smirnoff 583b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h> 59ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 603b3a8eb9SGleb Smirnoff 613b3a8eb9SGleb Smirnoff 623b3a8eb9SGleb Smirnoff /* 63b074b7bbSAlexander V. Chernikov * Table has the following `type` concepts: 64b074b7bbSAlexander V. Chernikov * 659f7d47b0SAlexander V. Chernikov * `no.type` represents lookup key type (cidr, ifp, uid, etc..) 669f7d47b0SAlexander V. Chernikov * `ta->atype` represents exact lookup algorithm. 67b074b7bbSAlexander V. Chernikov * For example, we can use more efficient search schemes if we plan 68b074b7bbSAlexander V. Chernikov * to use some specific table for storing host-routes only. 699490a627SAlexander V. Chernikov * `ftype` (at the moment )is pure userland field helping to properly 709490a627SAlexander V. Chernikov * format value data e.g. "value is IPv4 nexthop" or "value is DSCP" 719490a627SAlexander V. Chernikov * or "value is port". 72b074b7bbSAlexander V. Chernikov * 73b074b7bbSAlexander V. Chernikov */ 74b074b7bbSAlexander V. Chernikov struct table_config { 75b074b7bbSAlexander V. Chernikov struct named_object no; 76ac35ff17SAlexander V. Chernikov uint8_t vtype; /* format table type */ 77b074b7bbSAlexander V. Chernikov uint8_t linked; /* 1 if already linked */ 78914bffb6SAlexander V. Chernikov uint8_t tflags; /* type flags */ 79914bffb6SAlexander V. Chernikov uint8_t spare; 80b074b7bbSAlexander V. Chernikov uint32_t count; /* Number of records */ 814c0c07a5SAlexander V. Chernikov uint32_t limit; /* Max 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 88b074b7bbSAlexander V. Chernikov struct tables_config { 89b074b7bbSAlexander V. Chernikov struct namedobj_instance *namehash; 909f7d47b0SAlexander V. Chernikov int algo_count; 919f7d47b0SAlexander V. Chernikov struct table_algo *algo[256]; 9257a1cf95SAlexander V. Chernikov struct table_algo *def_algo[IPFW_TABLE_MAXTYPE + 1]; 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); 9768394ec8SAlexander V. Chernikov static struct table_config *alloc_table_config(struct ip_fw_chain *ch, 98914bffb6SAlexander V. Chernikov struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t tflags, 99914bffb6SAlexander V. Chernikov uint8_t vtype); 100b074b7bbSAlexander V. Chernikov static void free_table_config(struct namedobj_instance *ni, 101b074b7bbSAlexander V. Chernikov struct table_config *tc); 102db785d31SAlexander V. Chernikov static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, 1034c0c07a5SAlexander V. Chernikov char *aname, ipfw_xtable_info *i); 104b074b7bbSAlexander V. Chernikov static void link_table(struct ip_fw_chain *chain, struct table_config *tc); 105b074b7bbSAlexander V. Chernikov static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc); 106b074b7bbSAlexander V. Chernikov static void free_table_state(void **state, void **xstate, uint8_t type); 1072d99a349SAlexander V. Chernikov static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 1082d99a349SAlexander V. Chernikov struct sockopt_data *sd); 109ac35ff17SAlexander V. Chernikov static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 110ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i); 11181d3153dSAlexander V. Chernikov static int dump_table_tentry(void *e, void *arg); 112f1220db8SAlexander V. Chernikov static int dump_table_xentry(void *e, void *arg); 113b074b7bbSAlexander V. Chernikov 1142d99a349SAlexander V. Chernikov static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd); 1152d99a349SAlexander V. Chernikov static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd); 116db785d31SAlexander V. Chernikov static int ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 117ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 118db785d31SAlexander V. Chernikov static int ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 119ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 120ac35ff17SAlexander V. Chernikov 121b6ee846eSAlexander V. Chernikov static int check_table_space(struct ip_fw_chain *ch, struct table_config *tc, 122b6ee846eSAlexander V. Chernikov struct table_info *ti, uint32_t count); 123ac35ff17SAlexander V. Chernikov static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti); 124d3a4f924SAlexander V. Chernikov 1259f7d47b0SAlexander V. Chernikov static struct table_algo *find_table_algo(struct tables_config *tableconf, 1269490a627SAlexander V. Chernikov struct tid_info *ti, char *name); 127b074b7bbSAlexander V. Chernikov 128b074b7bbSAlexander V. Chernikov #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) 129b074b7bbSAlexander V. Chernikov #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) 1309f7d47b0SAlexander V. Chernikov #define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) 131b074b7bbSAlexander V. Chernikov 132b6ee846eSAlexander V. Chernikov #define TA_BUF_SZ 128 /* On-stack buffer for add/delete state */ 133b6ee846eSAlexander V. Chernikov 134b074b7bbSAlexander V. Chernikov 1353b3a8eb9SGleb Smirnoff int 1361832a7b3SAlexander V. Chernikov add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 137b6ee846eSAlexander V. Chernikov struct tentry_info *tei, uint32_t count) 1383b3a8eb9SGleb Smirnoff { 139db785d31SAlexander V. Chernikov struct table_config *tc; 1409f7d47b0SAlexander V. Chernikov struct table_algo *ta; 141b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 142b074b7bbSAlexander V. Chernikov uint16_t kidx; 1439f7d47b0SAlexander V. Chernikov int error; 144adea6201SAlexander V. Chernikov uint32_t num; 145b6ee846eSAlexander V. Chernikov ipfw_xtable_info *xi; 146b6ee846eSAlexander V. Chernikov char ta_buf[TA_BUF_SZ]; 1473b3a8eb9SGleb Smirnoff 1489f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1499f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1509f7d47b0SAlexander V. Chernikov 1519f7d47b0SAlexander V. Chernikov /* 1529f7d47b0SAlexander V. Chernikov * Find and reference existing table. 1539f7d47b0SAlexander V. Chernikov */ 1549f7d47b0SAlexander V. Chernikov ta = NULL; 1559f7d47b0SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1569f7d47b0SAlexander V. Chernikov /* check table type */ 1579f7d47b0SAlexander V. Chernikov if (tc->no.type != ti->type) { 1589f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1593b3a8eb9SGleb Smirnoff return (EINVAL); 1603b3a8eb9SGleb Smirnoff } 1613b3a8eb9SGleb Smirnoff 1624c0c07a5SAlexander V. Chernikov /* Try to exit early on limit hit */ 1634c0c07a5SAlexander V. Chernikov if (tc->limit != 0 && tc->count == tc->limit && 1644c0c07a5SAlexander V. Chernikov (tei->flags & TEI_FLAGS_UPDATE) == 0) { 1654c0c07a5SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1664c0c07a5SAlexander V. Chernikov return (EFBIG); 1674c0c07a5SAlexander V. Chernikov } 1684c0c07a5SAlexander V. Chernikov 1699f7d47b0SAlexander V. Chernikov /* Reference and unlock */ 1709f7d47b0SAlexander V. Chernikov tc->no.refcnt++; 1719f7d47b0SAlexander V. Chernikov ta = tc->ta; 1729f7d47b0SAlexander V. Chernikov } 1739f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1743b3a8eb9SGleb Smirnoff 175ac35ff17SAlexander V. Chernikov if (tc == NULL) { 176db785d31SAlexander V. Chernikov /* Compability mode: create new table for old clients */ 177db785d31SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_COMPAT) == 0) 178db785d31SAlexander V. Chernikov return (ESRCH); 1793b3a8eb9SGleb Smirnoff 180b6ee846eSAlexander V. Chernikov xi = malloc(sizeof(ipfw_xtable_info), M_TEMP, M_WAITOK|M_ZERO); 181b6ee846eSAlexander V. Chernikov xi->vtype = IPFW_VTYPE_U32; 1824c0c07a5SAlexander V. Chernikov 183b6ee846eSAlexander V. Chernikov error = create_table_internal(ch, ti, NULL, xi); 184b6ee846eSAlexander V. Chernikov free(xi, M_TEMP); 185db785d31SAlexander V. Chernikov 186db785d31SAlexander V. Chernikov if (error != 0) 187db785d31SAlexander V. Chernikov return (error); 188db785d31SAlexander V. Chernikov 189db785d31SAlexander V. Chernikov /* Let's try to find & reference another time */ 190db785d31SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 191db785d31SAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 192db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 193db785d31SAlexander V. Chernikov return (EINVAL); 194db785d31SAlexander V. Chernikov } 195db785d31SAlexander V. Chernikov 196db785d31SAlexander V. Chernikov if (tc->no.type != ti->type) { 197db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 198db785d31SAlexander V. Chernikov return (EINVAL); 199db785d31SAlexander V. Chernikov } 200db785d31SAlexander V. Chernikov 201db785d31SAlexander V. Chernikov /* Reference and unlock */ 202db785d31SAlexander V. Chernikov tc->no.refcnt++; 203db785d31SAlexander V. Chernikov ta = tc->ta; 204db785d31SAlexander V. Chernikov 205db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 206db785d31SAlexander V. Chernikov } 207db785d31SAlexander V. Chernikov 2089f7d47b0SAlexander V. Chernikov /* Prepare record (allocate memory) */ 2099f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 21068394ec8SAlexander V. Chernikov error = ta->prepare_add(ch, tei, &ta_buf); 211db785d31SAlexander V. Chernikov if (error != 0) 2129f7d47b0SAlexander V. Chernikov return (error); 2133b3a8eb9SGleb Smirnoff 214b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 2153b3a8eb9SGleb Smirnoff 216b6ee846eSAlexander V. Chernikov /* 217b6ee846eSAlexander V. Chernikov * Ensure we are able to add all entries without additional 218b6ee846eSAlexander V. Chernikov * memory allocations. May release/reacquire UH_WLOCK. 219b6ee846eSAlexander V. Chernikov */ 220b6ee846eSAlexander V. Chernikov kidx = tc->no.kidx; 221b6ee846eSAlexander V. Chernikov error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), count); 222b6ee846eSAlexander V. Chernikov if (error != 0) { 223b6ee846eSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 224b6ee846eSAlexander V. Chernikov ta->flush_entry(ch, tei, &ta_buf); 225b6ee846eSAlexander V. Chernikov return (error); 226b6ee846eSAlexander V. Chernikov } 227b6ee846eSAlexander V. Chernikov 228b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 2293b3a8eb9SGleb Smirnoff 2309f7d47b0SAlexander V. Chernikov /* Drop reference we've used in first search */ 2319f7d47b0SAlexander V. Chernikov tc->no.refcnt--; 232b074b7bbSAlexander V. Chernikov 2334c0c07a5SAlexander V. Chernikov /* Check limit before adding */ 2344c0c07a5SAlexander V. Chernikov if (tc->limit != 0 && tc->count == tc->limit) { 2354c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) { 2364c0c07a5SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 237b6ee846eSAlexander V. Chernikov ta->flush_entry(ch, tei, &ta_buf); 2384c0c07a5SAlexander V. Chernikov return (EFBIG); 2394c0c07a5SAlexander V. Chernikov } 2404c0c07a5SAlexander V. Chernikov 2414c0c07a5SAlexander V. Chernikov /* 2424c0c07a5SAlexander V. Chernikov * We have UPDATE flag set. 2434c0c07a5SAlexander V. Chernikov * Permit updating record (if found), 2444c0c07a5SAlexander V. Chernikov * but restrict adding new one since we've 2454c0c07a5SAlexander V. Chernikov * already hit the limit. 2464c0c07a5SAlexander V. Chernikov */ 2474c0c07a5SAlexander V. Chernikov tei->flags |= TEI_FLAGS_DONTADD; 2484c0c07a5SAlexander V. Chernikov } 2494c0c07a5SAlexander V. Chernikov 250b074b7bbSAlexander V. Chernikov /* We've got valid table in @tc. Let's add data */ 2519f7d47b0SAlexander V. Chernikov kidx = tc->no.kidx; 2529f7d47b0SAlexander V. Chernikov ta = tc->ta; 253adea6201SAlexander V. Chernikov num = 0; 2549f7d47b0SAlexander V. Chernikov 255b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 256b6ee846eSAlexander V. Chernikov error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, &num); 2573b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2589f7d47b0SAlexander V. Chernikov 259ac35ff17SAlexander V. Chernikov /* Update number of records. */ 260b6ee846eSAlexander V. Chernikov if (error == 0) { 261adea6201SAlexander V. Chernikov tc->count += num; 262b6ee846eSAlexander V. Chernikov /* Permit post-add algorithm grow/rehash. */ 263b6ee846eSAlexander V. Chernikov error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), 0); 264b6ee846eSAlexander V. Chernikov } 265db785d31SAlexander V. Chernikov 266b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 267b074b7bbSAlexander V. Chernikov 268ac35ff17SAlexander V. Chernikov /* Run cleaning callback anyway */ 26968394ec8SAlexander V. Chernikov ta->flush_entry(ch, tei, &ta_buf); 270b074b7bbSAlexander V. Chernikov 2719f7d47b0SAlexander V. Chernikov return (error); 2723b3a8eb9SGleb Smirnoff } 2733b3a8eb9SGleb Smirnoff 2743b3a8eb9SGleb Smirnoff int 2751832a7b3SAlexander V. Chernikov del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 276b6ee846eSAlexander V. Chernikov struct tentry_info *tei, uint32_t count) 2773b3a8eb9SGleb Smirnoff { 278b074b7bbSAlexander V. Chernikov struct table_config *tc; 2799f7d47b0SAlexander V. Chernikov struct table_algo *ta; 280b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 281b074b7bbSAlexander V. Chernikov uint16_t kidx; 2829f7d47b0SAlexander V. Chernikov int error; 283adea6201SAlexander V. Chernikov uint32_t num; 284b6ee846eSAlexander V. Chernikov char ta_buf[TA_BUF_SZ]; 2853b3a8eb9SGleb Smirnoff 2869f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 287b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 288b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 2899f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2903b3a8eb9SGleb Smirnoff return (ESRCH); 2913b3a8eb9SGleb Smirnoff } 2923b3a8eb9SGleb Smirnoff 293b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 2949f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2953b3a8eb9SGleb Smirnoff return (EINVAL); 2963b3a8eb9SGleb Smirnoff } 2979f7d47b0SAlexander V. Chernikov 2989f7d47b0SAlexander V. Chernikov ta = tc->ta; 2999f7d47b0SAlexander V. Chernikov 300db785d31SAlexander V. Chernikov /* 301b6ee846eSAlexander V. Chernikov * Give a chance for algorithm to shrink. 302b6ee846eSAlexander V. Chernikov * May release/reacquire UH_WLOCK. 303db785d31SAlexander V. Chernikov */ 304b6ee846eSAlexander V. Chernikov kidx = tc->no.kidx; 305b6ee846eSAlexander V. Chernikov error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), 0); 306db785d31SAlexander V. Chernikov if (error != 0) { 307db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 308b6ee846eSAlexander V. Chernikov ta->flush_entry(ch, tei, &ta_buf); 309db785d31SAlexander V. Chernikov return (error); 310db785d31SAlexander V. Chernikov } 311db785d31SAlexander V. Chernikov 312db785d31SAlexander V. Chernikov /* 313db785d31SAlexander V. Chernikov * We assume ta_buf size is enough for storing 314b6ee846eSAlexander V. Chernikov * prepare_del() key, so we're running under UH_WLOCK here. 315db785d31SAlexander V. Chernikov */ 3169f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 31768394ec8SAlexander V. Chernikov if ((error = ta->prepare_del(ch, tei, &ta_buf)) != 0) { 3189f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3199f7d47b0SAlexander V. Chernikov return (error); 3209f7d47b0SAlexander V. Chernikov } 3219f7d47b0SAlexander V. Chernikov 322b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 323adea6201SAlexander V. Chernikov num = 0; 324b074b7bbSAlexander V. Chernikov 325b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 326b6ee846eSAlexander V. Chernikov error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, &num); 3273b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 3283b3a8eb9SGleb Smirnoff 329b6ee846eSAlexander V. Chernikov if (error == 0) { 330adea6201SAlexander V. Chernikov tc->count -= num; 331b6ee846eSAlexander V. Chernikov /* Run post-del hook to permit shrinking */ 332b6ee846eSAlexander V. Chernikov error = check_table_space(ch, tc, KIDX_TO_TI(ch, kidx), 0); 333b6ee846eSAlexander V. Chernikov } 334b074b7bbSAlexander V. Chernikov 3359f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3363b3a8eb9SGleb Smirnoff 33768394ec8SAlexander V. Chernikov ta->flush_entry(ch, tei, &ta_buf); 338ac35ff17SAlexander V. Chernikov 339ac35ff17SAlexander V. Chernikov return (error); 340ac35ff17SAlexander V. Chernikov } 341ac35ff17SAlexander V. Chernikov 342db785d31SAlexander V. Chernikov /* 343b6ee846eSAlexander V. Chernikov * Ensure that table @tc has enough space to add @count entries without 344b6ee846eSAlexander V. Chernikov * need for reallocation. 345db785d31SAlexander V. Chernikov * 346db785d31SAlexander V. Chernikov * Callbacks order: 347b6ee846eSAlexander V. Chernikov * 0) has_space() (UH_WLOCK) - checks if @count items can be added w/o resize. 348b6ee846eSAlexander V. Chernikov * 349db785d31SAlexander V. Chernikov * 1) alloc_modify (no locks, M_WAITOK) - alloc new state based on @pflags. 350db785d31SAlexander V. Chernikov * 2) prepare_modifyt (UH_WLOCK) - copy old data into new storage 351db785d31SAlexander V. Chernikov * 3) modify (UH_WLOCK + WLOCK) - switch pointers 352b6ee846eSAlexander V. Chernikov * 4) flush_modify (UH_WLOCK) - free state, if needed 353b6ee846eSAlexander V. Chernikov * 354b6ee846eSAlexander V. Chernikov * Returns 0 on success. 355db785d31SAlexander V. Chernikov */ 356db785d31SAlexander V. Chernikov static int 357b6ee846eSAlexander V. Chernikov check_table_space(struct ip_fw_chain *ch, struct table_config *tc, 358b6ee846eSAlexander V. Chernikov struct table_info *ti, uint32_t count) 359db785d31SAlexander V. Chernikov { 360b6ee846eSAlexander V. Chernikov struct table_algo *ta; 361b6ee846eSAlexander V. Chernikov uint64_t pflags; 362b6ee846eSAlexander V. Chernikov char ta_buf[TA_BUF_SZ]; 363db785d31SAlexander V. Chernikov int error; 364db785d31SAlexander V. Chernikov 365b6ee846eSAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 366db785d31SAlexander V. Chernikov 367b6ee846eSAlexander V. Chernikov error = 0; 368b6ee846eSAlexander V. Chernikov ta = tc->ta; 369b6ee846eSAlexander V. Chernikov /* Acquire reference not to loose @tc between locks/unlocks */ 370b6ee846eSAlexander V. Chernikov tc->no.refcnt++; 371db785d31SAlexander V. Chernikov 372db785d31SAlexander V. Chernikov /* 373b6ee846eSAlexander V. Chernikov * TODO: think about avoiding race between large add/large delete 374b6ee846eSAlexander V. Chernikov * operation on algorithm which implements shrinking along with 375b6ee846eSAlexander V. Chernikov * growing. 376db785d31SAlexander V. Chernikov */ 377b6ee846eSAlexander V. Chernikov while (true) { 378b6ee846eSAlexander V. Chernikov pflags = 0; 379b6ee846eSAlexander V. Chernikov if (ta->has_space(tc->astate, ti, count, &pflags) != 0) { 380b6ee846eSAlexander V. Chernikov tc->no.refcnt--; 381b6ee846eSAlexander V. Chernikov return (0); 382b6ee846eSAlexander V. Chernikov } 383db785d31SAlexander V. Chernikov 384b6ee846eSAlexander V. Chernikov /* We have to shrink/grow table */ 385b6ee846eSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 386b6ee846eSAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 387b6ee846eSAlexander V. Chernikov 388b6ee846eSAlexander V. Chernikov if ((error = ta->prepare_mod(ta_buf, &pflags)) != 0) { 389b6ee846eSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 390b6ee846eSAlexander V. Chernikov break; 391b6ee846eSAlexander V. Chernikov } 392b6ee846eSAlexander V. Chernikov 393b6ee846eSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 394b6ee846eSAlexander V. Chernikov 395b6ee846eSAlexander V. Chernikov /* Check if we still need to alter table */ 396b6ee846eSAlexander V. Chernikov ti = KIDX_TO_TI(ch, tc->no.kidx); 397b6ee846eSAlexander V. Chernikov if (ta->has_space(tc->astate, ti, count, &pflags) != 0) { 398b6ee846eSAlexander V. Chernikov 399b6ee846eSAlexander V. Chernikov /* 400b6ee846eSAlexander V. Chernikov * Other threads has already performed resize. 401b6ee846eSAlexander V. Chernikov * Flush our state and return/ 402b6ee846eSAlexander V. Chernikov */ 403b6ee846eSAlexander V. Chernikov ta->flush_mod(ta_buf); 404b6ee846eSAlexander V. Chernikov break; 405b6ee846eSAlexander V. Chernikov } 406b6ee846eSAlexander V. Chernikov 407b6ee846eSAlexander V. Chernikov error = ta->fill_mod(tc->astate, ti, ta_buf, &pflags); 408b6ee846eSAlexander V. Chernikov if (error == 0) { 409db785d31SAlexander V. Chernikov /* Do actual modification */ 410db785d31SAlexander V. Chernikov IPFW_WLOCK(ch); 41168394ec8SAlexander V. Chernikov ta->modify(tc->astate, ti, ta_buf, pflags); 412db785d31SAlexander V. Chernikov IPFW_WUNLOCK(ch); 413db785d31SAlexander V. Chernikov } 414db785d31SAlexander V. Chernikov 415b6ee846eSAlexander V. Chernikov /* Anyway, flush data and retry */ 416db785d31SAlexander V. Chernikov ta->flush_mod(ta_buf); 417b6ee846eSAlexander V. Chernikov } 418db785d31SAlexander V. Chernikov 419b6ee846eSAlexander V. Chernikov tc->no.refcnt--; 420db785d31SAlexander V. Chernikov return (error); 421db785d31SAlexander V. Chernikov } 422db785d31SAlexander V. Chernikov 423b6ee846eSAlexander V. Chernikov 424b6ee846eSAlexander V. Chernikov 425ac35ff17SAlexander V. Chernikov int 426db785d31SAlexander V. Chernikov ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 427ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 428ac35ff17SAlexander V. Chernikov { 429ac35ff17SAlexander V. Chernikov int error; 430ac35ff17SAlexander V. Chernikov 431ac35ff17SAlexander V. Chernikov switch (op3->version) { 432ac35ff17SAlexander V. Chernikov case 0: 433db785d31SAlexander V. Chernikov error = ipfw_manage_table_ent_v0(ch, op3, sd); 434ac35ff17SAlexander V. Chernikov break; 435ac35ff17SAlexander V. Chernikov case 1: 436db785d31SAlexander V. Chernikov error = ipfw_manage_table_ent_v1(ch, op3, sd); 437ac35ff17SAlexander V. Chernikov break; 438ac35ff17SAlexander V. Chernikov default: 439ac35ff17SAlexander V. Chernikov error = ENOTSUP; 440ac35ff17SAlexander V. Chernikov } 441ac35ff17SAlexander V. Chernikov 442ac35ff17SAlexander V. Chernikov return (error); 443ac35ff17SAlexander V. Chernikov } 444ac35ff17SAlexander V. Chernikov 445ac35ff17SAlexander V. Chernikov /* 446ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 447ac35ff17SAlexander V. Chernikov * Data layout (v0): 448ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ipfw_table_xentry ] 449ac35ff17SAlexander V. Chernikov * 450ac35ff17SAlexander V. Chernikov * Returns 0 on success 451ac35ff17SAlexander V. Chernikov */ 452ac35ff17SAlexander V. Chernikov static int 453db785d31SAlexander V. Chernikov ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 454ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 455ac35ff17SAlexander V. Chernikov { 456ac35ff17SAlexander V. Chernikov ipfw_table_xentry *xent; 457ac35ff17SAlexander V. Chernikov struct tentry_info tei; 458ac35ff17SAlexander V. Chernikov struct tid_info ti; 459ac35ff17SAlexander V. Chernikov int error, hdrlen, read; 460ac35ff17SAlexander V. Chernikov 461ac35ff17SAlexander V. Chernikov hdrlen = offsetof(ipfw_table_xentry, k); 462ac35ff17SAlexander V. Chernikov 463ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 464ac35ff17SAlexander V. Chernikov if (sd->valsize < (sizeof(*op3) + hdrlen)) 465ac35ff17SAlexander V. Chernikov return (EINVAL); 466ac35ff17SAlexander V. Chernikov 467ac35ff17SAlexander V. Chernikov read = sizeof(ip_fw3_opheader); 468ac35ff17SAlexander V. Chernikov 469ac35ff17SAlexander V. Chernikov /* Check if xentry len field is valid */ 470ac35ff17SAlexander V. Chernikov xent = (ipfw_table_xentry *)(op3 + 1); 471ac35ff17SAlexander V. Chernikov if (xent->len < hdrlen || xent->len + read > sd->valsize) 472ac35ff17SAlexander V. Chernikov return (EINVAL); 473ac35ff17SAlexander V. Chernikov 474ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 475ac35ff17SAlexander V. Chernikov tei.paddr = &xent->k; 476ac35ff17SAlexander V. Chernikov tei.masklen = xent->masklen; 477ac35ff17SAlexander V. Chernikov tei.value = xent->value; 478ac35ff17SAlexander V. Chernikov /* Old requests compability */ 479db785d31SAlexander V. Chernikov tei.flags = TEI_FLAGS_COMPAT; 480ac35ff17SAlexander V. Chernikov if (xent->type == IPFW_TABLE_CIDR) { 481ac35ff17SAlexander V. Chernikov if (xent->len - hdrlen == sizeof(in_addr_t)) 482ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET; 483ac35ff17SAlexander V. Chernikov else 484ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET6; 485ac35ff17SAlexander V. Chernikov } 486ac35ff17SAlexander V. Chernikov 487ac35ff17SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 488ac35ff17SAlexander V. Chernikov ti.uidx = xent->tbl; 489ac35ff17SAlexander V. Chernikov ti.type = xent->type; 490ac35ff17SAlexander V. Chernikov 491ac35ff17SAlexander V. Chernikov error = (op3->opcode == IP_FW_TABLE_XADD) ? 492b6ee846eSAlexander V. Chernikov add_table_entry(ch, &ti, &tei, 1) : 493b6ee846eSAlexander V. Chernikov del_table_entry(ch, &ti, &tei, 1); 494ac35ff17SAlexander V. Chernikov 495ac35ff17SAlexander V. Chernikov return (error); 496ac35ff17SAlexander V. Chernikov } 497ac35ff17SAlexander V. Chernikov 498ac35ff17SAlexander V. Chernikov /* 499ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 500ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 501db785d31SAlexander V. Chernikov * Request: [ ipfw_obj_header 502db785d31SAlexander V. Chernikov * ipfw_obj_ctlv(IPFW_TLV_TBLENT_LIST) [ ipfw_obj_tentry x N ] 503db785d31SAlexander V. Chernikov * ] 504ac35ff17SAlexander V. Chernikov * 505ac35ff17SAlexander V. Chernikov * Returns 0 on success 506ac35ff17SAlexander V. Chernikov */ 507ac35ff17SAlexander V. Chernikov static int 508db785d31SAlexander V. Chernikov ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 509ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 510ac35ff17SAlexander V. Chernikov { 511ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent; 512db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 513ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 514ac35ff17SAlexander V. Chernikov struct tentry_info tei; 515ac35ff17SAlexander V. Chernikov struct tid_info ti; 516ac35ff17SAlexander V. Chernikov int error, read; 517ac35ff17SAlexander V. Chernikov 518ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 519db785d31SAlexander V. Chernikov if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv))) 520ac35ff17SAlexander V. Chernikov return (EINVAL); 521ac35ff17SAlexander V. Chernikov 522ac35ff17SAlexander V. Chernikov /* Check if passed data is too long */ 523ac35ff17SAlexander V. Chernikov if (sd->valsize != sd->kavail) 524ac35ff17SAlexander V. Chernikov return (EINVAL); 525ac35ff17SAlexander V. Chernikov 526ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)sd->kbuf; 527ac35ff17SAlexander V. Chernikov 528ac35ff17SAlexander V. Chernikov /* Basic length checks for TLVs */ 529ac35ff17SAlexander V. Chernikov if (oh->ntlv.head.length != sizeof(oh->ntlv)) 530ac35ff17SAlexander V. Chernikov return (EINVAL); 531ac35ff17SAlexander V. Chernikov 532ac35ff17SAlexander V. Chernikov read = sizeof(*oh); 533ac35ff17SAlexander V. Chernikov 534db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 535db785d31SAlexander V. Chernikov if (ctlv->head.length + read != sd->valsize) 536db785d31SAlexander V. Chernikov return (EINVAL); 537db785d31SAlexander V. Chernikov 538db785d31SAlexander V. Chernikov /* 539db785d31SAlexander V. Chernikov * TODO: permit adding multiple entries for given table 540db785d31SAlexander V. Chernikov * at once 541db785d31SAlexander V. Chernikov */ 542db785d31SAlexander V. Chernikov if (ctlv->count != 1) 543db785d31SAlexander V. Chernikov return (EOPNOTSUPP); 544db785d31SAlexander V. Chernikov 545db785d31SAlexander V. Chernikov read += sizeof(*ctlv); 546db785d31SAlexander V. Chernikov 547ac35ff17SAlexander V. Chernikov /* Assume tentry may grow to support larger keys */ 548db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 549ac35ff17SAlexander V. Chernikov if (tent->head.length < sizeof(*tent) || 550ac35ff17SAlexander V. Chernikov tent->head.length + read > sd->valsize) 551ac35ff17SAlexander V. Chernikov return (EINVAL); 552ac35ff17SAlexander V. Chernikov 55381d3153dSAlexander V. Chernikov /* Convert data into kernel request objects */ 554ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 555ac35ff17SAlexander V. Chernikov tei.paddr = &tent->k; 556ac35ff17SAlexander V. Chernikov tei.subtype = tent->subtype; 557ac35ff17SAlexander V. Chernikov tei.masklen = tent->masklen; 55881d3153dSAlexander V. Chernikov if (tent->head.flags & IPFW_TF_UPDATE) 559ac35ff17SAlexander V. Chernikov tei.flags |= TEI_FLAGS_UPDATE; 560ac35ff17SAlexander V. Chernikov tei.value = tent->value; 561ac35ff17SAlexander V. Chernikov 56281d3153dSAlexander V. Chernikov objheader_to_ti(oh, &ti); 563ac35ff17SAlexander V. Chernikov ti.type = oh->ntlv.type; 56481d3153dSAlexander V. Chernikov ti.uidx = tent->idx; 565ac35ff17SAlexander V. Chernikov 566ac35ff17SAlexander V. Chernikov error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ? 567b6ee846eSAlexander V. Chernikov add_table_entry(ch, &ti, &tei, 1) : 568b6ee846eSAlexander V. Chernikov del_table_entry(ch, &ti, &tei, 1); 569ac35ff17SAlexander V. Chernikov 570ac35ff17SAlexander V. Chernikov return (error); 571ac35ff17SAlexander V. Chernikov } 572ac35ff17SAlexander V. Chernikov 57381d3153dSAlexander V. Chernikov /* 57481d3153dSAlexander V. Chernikov * Looks up an entry in given table. 57581d3153dSAlexander V. Chernikov * Data layout (v0)(current): 57681d3153dSAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_obj_tentry ] 57781d3153dSAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_obj_tentry ] 57881d3153dSAlexander V. Chernikov * 57981d3153dSAlexander V. Chernikov * Returns 0 on success 58081d3153dSAlexander V. Chernikov */ 58181d3153dSAlexander V. Chernikov int 58281d3153dSAlexander V. Chernikov ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 58381d3153dSAlexander V. Chernikov struct sockopt_data *sd) 58481d3153dSAlexander V. Chernikov { 58581d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 58681d3153dSAlexander V. Chernikov ipfw_obj_header *oh; 58781d3153dSAlexander V. Chernikov struct tid_info ti; 58881d3153dSAlexander V. Chernikov struct table_config *tc; 58981d3153dSAlexander V. Chernikov struct table_algo *ta; 59081d3153dSAlexander V. Chernikov struct table_info *kti; 59181d3153dSAlexander V. Chernikov struct namedobj_instance *ni; 592914bffb6SAlexander V. Chernikov int error; 59381d3153dSAlexander V. Chernikov size_t sz; 59481d3153dSAlexander V. Chernikov 59581d3153dSAlexander V. Chernikov /* Check minimum header size */ 59681d3153dSAlexander V. Chernikov sz = sizeof(*oh) + sizeof(*tent); 59781d3153dSAlexander V. Chernikov if (sd->valsize != sz) 59881d3153dSAlexander V. Chernikov return (EINVAL); 59981d3153dSAlexander V. Chernikov 60081d3153dSAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 60181d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 60281d3153dSAlexander V. Chernikov 60381d3153dSAlexander V. Chernikov /* Basic length checks for TLVs */ 60481d3153dSAlexander V. Chernikov if (oh->ntlv.head.length != sizeof(oh->ntlv)) 60581d3153dSAlexander V. Chernikov return (EINVAL); 60681d3153dSAlexander V. Chernikov 60781d3153dSAlexander V. Chernikov objheader_to_ti(oh, &ti); 60881d3153dSAlexander V. Chernikov ti.type = oh->ntlv.type; 60981d3153dSAlexander V. Chernikov ti.uidx = tent->idx; 61081d3153dSAlexander V. Chernikov 61181d3153dSAlexander V. Chernikov IPFW_UH_RLOCK(ch); 61281d3153dSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 61381d3153dSAlexander V. Chernikov 61481d3153dSAlexander V. Chernikov /* 61581d3153dSAlexander V. Chernikov * Find existing table and check its type . 61681d3153dSAlexander V. Chernikov */ 61781d3153dSAlexander V. Chernikov ta = NULL; 61881d3153dSAlexander V. Chernikov if ((tc = find_table(ni, &ti)) == NULL) { 61981d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 62081d3153dSAlexander V. Chernikov return (ESRCH); 62181d3153dSAlexander V. Chernikov } 62281d3153dSAlexander V. Chernikov 62381d3153dSAlexander V. Chernikov /* check table type */ 62481d3153dSAlexander V. Chernikov if (tc->no.type != ti.type) { 62581d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 62681d3153dSAlexander V. Chernikov return (EINVAL); 62781d3153dSAlexander V. Chernikov } 62881d3153dSAlexander V. Chernikov 62981d3153dSAlexander V. Chernikov kti = KIDX_TO_TI(ch, tc->no.kidx); 63081d3153dSAlexander V. Chernikov ta = tc->ta; 63181d3153dSAlexander V. Chernikov 632914bffb6SAlexander V. Chernikov if (ta->find_tentry == NULL) 633914bffb6SAlexander V. Chernikov return (ENOTSUP); 634914bffb6SAlexander V. Chernikov 635914bffb6SAlexander V. Chernikov error = ta->find_tentry(tc->astate, kti, tent); 63681d3153dSAlexander V. Chernikov 63781d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 63881d3153dSAlexander V. Chernikov 63981d3153dSAlexander V. Chernikov return (error); 64081d3153dSAlexander V. Chernikov } 64181d3153dSAlexander V. Chernikov 642ac35ff17SAlexander V. Chernikov int 643ac35ff17SAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 644ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 645ac35ff17SAlexander V. Chernikov { 646ac35ff17SAlexander V. Chernikov int error; 647ac35ff17SAlexander V. Chernikov struct _ipfw_obj_header *oh; 648ac35ff17SAlexander V. Chernikov struct tid_info ti; 649ac35ff17SAlexander V. Chernikov 650ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh)) 651ac35ff17SAlexander V. Chernikov return (EINVAL); 652ac35ff17SAlexander V. Chernikov 653ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)op3; 654ac35ff17SAlexander V. Chernikov objheader_to_ti(oh, &ti); 655ac35ff17SAlexander V. Chernikov 6561832a7b3SAlexander V. Chernikov if (op3->opcode == IP_FW_TABLE_XDESTROY) 657ac35ff17SAlexander V. Chernikov error = destroy_table(ch, &ti); 6581832a7b3SAlexander V. Chernikov else if (op3->opcode == IP_FW_TABLE_XFLUSH) 659ac35ff17SAlexander V. Chernikov error = flush_table(ch, &ti); 660ac35ff17SAlexander V. Chernikov else 661ac35ff17SAlexander V. Chernikov return (ENOTSUP); 662ac35ff17SAlexander V. Chernikov 663ac35ff17SAlexander V. Chernikov return (error); 6643b3a8eb9SGleb Smirnoff } 6653b3a8eb9SGleb Smirnoff 666b074b7bbSAlexander V. Chernikov /* 6679f7d47b0SAlexander V. Chernikov * Flushes all entries in given table. 668ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 669ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 670ac35ff17SAlexander V. Chernikov * 671ac35ff17SAlexander V. Chernikov * Returns 0 on success 672b074b7bbSAlexander V. Chernikov */ 6731832a7b3SAlexander V. Chernikov int 674ac35ff17SAlexander V. Chernikov flush_table(struct ip_fw_chain *ch, struct tid_info *ti) 6753b3a8eb9SGleb Smirnoff { 676b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 677b074b7bbSAlexander V. Chernikov struct table_config *tc; 6789f7d47b0SAlexander V. Chernikov struct table_algo *ta; 6799f7d47b0SAlexander V. Chernikov struct table_info ti_old, ti_new, *tablestate; 6809f7d47b0SAlexander V. Chernikov void *astate_old, *astate_new; 681914bffb6SAlexander V. Chernikov char algostate[64], *pstate; 682b074b7bbSAlexander V. Chernikov int error; 683b074b7bbSAlexander V. Chernikov uint16_t kidx; 684914bffb6SAlexander V. Chernikov uint8_t tflags; 6853b3a8eb9SGleb Smirnoff 6863b3a8eb9SGleb Smirnoff /* 6879f7d47b0SAlexander V. Chernikov * Stage 1: save table algoritm. 688b074b7bbSAlexander V. Chernikov * Reference found table to ensure it won't disappear. 6893b3a8eb9SGleb Smirnoff */ 690b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 691b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 692b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 693b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 694b074b7bbSAlexander V. Chernikov return (ESRCH); 695b074b7bbSAlexander V. Chernikov } 6969f7d47b0SAlexander V. Chernikov ta = tc->ta; 697b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 698daabb523SAlexander V. Chernikov /* Save statup algo parameters */ 699daabb523SAlexander V. Chernikov if (ta->print_config != NULL) { 700daabb523SAlexander V. Chernikov ta->print_config(tc->astate, KIDX_TO_TI(ch, tc->no.kidx), 701daabb523SAlexander V. Chernikov algostate, sizeof(algostate)); 702daabb523SAlexander V. Chernikov pstate = algostate; 703daabb523SAlexander V. Chernikov } else 704daabb523SAlexander V. Chernikov pstate = NULL; 705914bffb6SAlexander V. Chernikov tflags = tc->tflags; 706b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 7073b3a8eb9SGleb Smirnoff 708b074b7bbSAlexander V. Chernikov /* 7099f7d47b0SAlexander V. Chernikov * Stage 2: allocate new table instance using same algo. 710b074b7bbSAlexander V. Chernikov */ 7119f7d47b0SAlexander V. Chernikov memset(&ti_new, 0, sizeof(struct table_info)); 712914bffb6SAlexander V. Chernikov if ((error = ta->init(ch, &astate_new, &ti_new, pstate, tflags)) != 0) { 713b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 714b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 715b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 716b074b7bbSAlexander V. Chernikov return (error); 717b074b7bbSAlexander V. Chernikov } 718b074b7bbSAlexander V. Chernikov 719b074b7bbSAlexander V. Chernikov /* 720b074b7bbSAlexander V. Chernikov * Stage 3: swap old state pointers with newly-allocated ones. 721b074b7bbSAlexander V. Chernikov * Decrease refcount. 722b074b7bbSAlexander V. Chernikov */ 723b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 724b074b7bbSAlexander V. Chernikov 725b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 726b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 7279f7d47b0SAlexander V. Chernikov tablestate = (struct table_info *)ch->tablestate; 728b074b7bbSAlexander V. Chernikov 7299f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 7309f7d47b0SAlexander V. Chernikov ti_old = tablestate[kidx]; 7319f7d47b0SAlexander V. Chernikov tablestate[kidx] = ti_new; 7329f7d47b0SAlexander V. Chernikov IPFW_WUNLOCK(ch); 733b074b7bbSAlexander V. Chernikov 7349f7d47b0SAlexander V. Chernikov astate_old = tc->astate; 7359f7d47b0SAlexander V. Chernikov tc->astate = astate_new; 7369f7d47b0SAlexander V. Chernikov tc->ti = ti_new; 7379f7d47b0SAlexander V. Chernikov tc->count = 0; 738b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 739b074b7bbSAlexander V. Chernikov 740b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 7413b3a8eb9SGleb Smirnoff 742b074b7bbSAlexander V. Chernikov /* 743b074b7bbSAlexander V. Chernikov * Stage 4: perform real flush. 744b074b7bbSAlexander V. Chernikov */ 7459f7d47b0SAlexander V. Chernikov ta->destroy(astate_old, &ti_old); 7463b3a8eb9SGleb Smirnoff 7473b3a8eb9SGleb Smirnoff return (0); 7483b3a8eb9SGleb Smirnoff } 7493b3a8eb9SGleb Smirnoff 750b074b7bbSAlexander V. Chernikov /* 7519f7d47b0SAlexander V. Chernikov * Destroys table specified by @ti. 752ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 753ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 754ac35ff17SAlexander V. Chernikov * 755ac35ff17SAlexander V. Chernikov * Returns 0 on success 756b074b7bbSAlexander V. Chernikov */ 757ac35ff17SAlexander V. Chernikov static int 758ac35ff17SAlexander V. Chernikov destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) 759b074b7bbSAlexander V. Chernikov { 760b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 761b074b7bbSAlexander V. Chernikov struct table_config *tc; 762b074b7bbSAlexander V. Chernikov 763b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 764b074b7bbSAlexander V. Chernikov 765b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 766b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 767b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 768b074b7bbSAlexander V. Chernikov return (ESRCH); 769b074b7bbSAlexander V. Chernikov } 770b074b7bbSAlexander V. Chernikov 7719f7d47b0SAlexander V. Chernikov /* Do not permit destroying referenced tables */ 7729f7d47b0SAlexander V. Chernikov if (tc->no.refcnt > 0) { 773b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 774b074b7bbSAlexander V. Chernikov return (EBUSY); 775b074b7bbSAlexander V. Chernikov } 776b074b7bbSAlexander V. Chernikov 777b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 778b074b7bbSAlexander V. Chernikov unlink_table(ch, tc); 779b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 780b074b7bbSAlexander V. Chernikov 781b074b7bbSAlexander V. Chernikov /* Free obj index */ 782ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0) 783b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 784b074b7bbSAlexander V. Chernikov tc->no.kidx, tc->tablename); 785b074b7bbSAlexander V. Chernikov 786b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 787b074b7bbSAlexander V. Chernikov 788b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 789b074b7bbSAlexander V. Chernikov 790b074b7bbSAlexander V. Chernikov return (0); 791b074b7bbSAlexander V. Chernikov } 792b074b7bbSAlexander V. Chernikov 793b074b7bbSAlexander V. Chernikov static void 794b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, 795b074b7bbSAlexander V. Chernikov void *arg) 796b074b7bbSAlexander V. Chernikov { 797b074b7bbSAlexander V. Chernikov 798b074b7bbSAlexander V. Chernikov unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); 799ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, no->kidx) != 0) 800b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 801b074b7bbSAlexander V. Chernikov no->kidx, no->name); 802b074b7bbSAlexander V. Chernikov free_table_config(ni, (struct table_config *)no); 803b074b7bbSAlexander V. Chernikov } 804b074b7bbSAlexander V. Chernikov 8053b3a8eb9SGleb Smirnoff void 8063b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch) 8073b3a8eb9SGleb Smirnoff { 8083b3a8eb9SGleb Smirnoff 809b074b7bbSAlexander V. Chernikov /* Remove all tables from working set */ 810b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 811b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 812b074b7bbSAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); 813b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 814b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 8153b3a8eb9SGleb Smirnoff 8163b3a8eb9SGleb Smirnoff /* Free pointers itself */ 8179f7d47b0SAlexander V. Chernikov free(ch->tablestate, M_IPFW); 8189f7d47b0SAlexander V. Chernikov 8199f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(ch); 820b074b7bbSAlexander V. Chernikov 821b074b7bbSAlexander V. Chernikov ipfw_objhash_destroy(CHAIN_TO_NI(ch)); 822b074b7bbSAlexander V. Chernikov free(CHAIN_TO_TCFG(ch), M_IPFW); 8233b3a8eb9SGleb Smirnoff } 8243b3a8eb9SGleb Smirnoff 8253b3a8eb9SGleb Smirnoff int 8263b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch) 8273b3a8eb9SGleb Smirnoff { 828b074b7bbSAlexander V. Chernikov struct tables_config *tcfg; 829b074b7bbSAlexander V. Chernikov 8303b3a8eb9SGleb Smirnoff /* Allocate pointers */ 8319f7d47b0SAlexander V. Chernikov ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), 8329f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 833b074b7bbSAlexander V. Chernikov 834b074b7bbSAlexander V. Chernikov tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); 835b074b7bbSAlexander V. Chernikov tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); 836b074b7bbSAlexander V. Chernikov ch->tblcfg = tcfg; 837b074b7bbSAlexander V. Chernikov 8389f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(ch); 8399f7d47b0SAlexander V. Chernikov 8403b3a8eb9SGleb Smirnoff return (0); 8413b3a8eb9SGleb Smirnoff } 8423b3a8eb9SGleb Smirnoff 8433b3a8eb9SGleb Smirnoff int 8443b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) 8453b3a8eb9SGleb Smirnoff { 8463b3a8eb9SGleb Smirnoff unsigned int ntables_old, tbl; 847b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 8489f7d47b0SAlexander V. Chernikov void *new_idx, *old_tablestate, *tablestate; 84968394ec8SAlexander V. Chernikov struct table_info *ti; 85068394ec8SAlexander V. Chernikov struct table_config *tc; 85168394ec8SAlexander V. Chernikov int i, new_blocks; 8523b3a8eb9SGleb Smirnoff 8533b3a8eb9SGleb Smirnoff /* Check new value for validity */ 8543b3a8eb9SGleb Smirnoff if (ntables > IPFW_TABLES_MAX) 8553b3a8eb9SGleb Smirnoff ntables = IPFW_TABLES_MAX; 8563b3a8eb9SGleb Smirnoff 8573b3a8eb9SGleb Smirnoff /* Allocate new pointers */ 8589f7d47b0SAlexander V. Chernikov tablestate = malloc(ntables * sizeof(struct table_info), 8599f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 8609f7d47b0SAlexander V. Chernikov 861b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); 8623b3a8eb9SGleb Smirnoff 8639f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 8643b3a8eb9SGleb Smirnoff 8653b3a8eb9SGleb Smirnoff tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables; 866b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 867b074b7bbSAlexander V. Chernikov 8689f7d47b0SAlexander V. Chernikov /* Temporary restrict decreasing max_tables */ 8699f7d47b0SAlexander V. Chernikov if (ntables < V_fw_tables_max) { 8709f7d47b0SAlexander V. Chernikov 8719f7d47b0SAlexander V. Chernikov /* 8729f7d47b0SAlexander V. Chernikov * FIXME: Check if we really can shrink 8739f7d47b0SAlexander V. Chernikov */ 8749f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 875b074b7bbSAlexander V. Chernikov return (EINVAL); 876b074b7bbSAlexander V. Chernikov } 8773b3a8eb9SGleb Smirnoff 8789f7d47b0SAlexander V. Chernikov /* Copy table info/indices */ 8799f7d47b0SAlexander V. Chernikov memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl); 8809f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks); 8813b3a8eb9SGleb Smirnoff 8829f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 8839f7d47b0SAlexander V. Chernikov 8849f7d47b0SAlexander V. Chernikov /* Change pointers */ 8859f7d47b0SAlexander V. Chernikov old_tablestate = ch->tablestate; 8869f7d47b0SAlexander V. Chernikov ch->tablestate = tablestate; 8879f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks); 8883b3a8eb9SGleb Smirnoff 8893b3a8eb9SGleb Smirnoff ntables_old = V_fw_tables_max; 8903b3a8eb9SGleb Smirnoff V_fw_tables_max = ntables; 8913b3a8eb9SGleb Smirnoff 8923b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 89368394ec8SAlexander V. Chernikov 89468394ec8SAlexander V. Chernikov /* Notify all consumers that their @ti pointer has changed */ 89568394ec8SAlexander V. Chernikov ti = (struct table_info *)ch->tablestate; 89668394ec8SAlexander V. Chernikov for (i = 0; i < tbl; i++, ti++) { 89768394ec8SAlexander V. Chernikov if (ti->lookup == NULL) 89868394ec8SAlexander V. Chernikov continue; 89968394ec8SAlexander V. Chernikov tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, i); 90068394ec8SAlexander V. Chernikov if (tc == NULL || tc->ta->change_ti == NULL) 90168394ec8SAlexander V. Chernikov continue; 90268394ec8SAlexander V. Chernikov 90368394ec8SAlexander V. Chernikov tc->ta->change_ti(tc->astate, ti); 90468394ec8SAlexander V. Chernikov } 90568394ec8SAlexander V. Chernikov 9069f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 9073b3a8eb9SGleb Smirnoff 9083b3a8eb9SGleb Smirnoff /* Free old pointers */ 9099f7d47b0SAlexander V. Chernikov free(old_tablestate, M_IPFW); 910b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 9113b3a8eb9SGleb Smirnoff 9123b3a8eb9SGleb Smirnoff return (0); 9133b3a8eb9SGleb Smirnoff } 9143b3a8eb9SGleb Smirnoff 9153b3a8eb9SGleb Smirnoff int 9163b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 9173b3a8eb9SGleb Smirnoff uint32_t *val) 9183b3a8eb9SGleb Smirnoff { 9199f7d47b0SAlexander V. Chernikov struct table_info *ti; 9203b3a8eb9SGleb Smirnoff 9219f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 9229f7d47b0SAlexander V. Chernikov 9239f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, &addr, sizeof(in_addr_t), val)); 9243b3a8eb9SGleb Smirnoff } 9259f7d47b0SAlexander V. Chernikov 9269f7d47b0SAlexander V. Chernikov int 9279f7d47b0SAlexander V. Chernikov ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, 9289f7d47b0SAlexander V. Chernikov void *paddr, uint32_t *val) 9299f7d47b0SAlexander V. Chernikov { 9309f7d47b0SAlexander V. Chernikov struct table_info *ti; 9319f7d47b0SAlexander V. Chernikov 9329f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 9339f7d47b0SAlexander V. Chernikov 9349f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, paddr, plen, val)); 9359f7d47b0SAlexander V. Chernikov } 9369f7d47b0SAlexander V. Chernikov 9379f7d47b0SAlexander V. Chernikov /* 9389f7d47b0SAlexander V. Chernikov * Info/List/dump support for tables. 9399f7d47b0SAlexander V. Chernikov * 9409f7d47b0SAlexander V. Chernikov */ 9419f7d47b0SAlexander V. Chernikov 942f1220db8SAlexander V. Chernikov /* 943d3a4f924SAlexander V. Chernikov * High-level 'get' cmds sysctl handlers 944d3a4f924SAlexander V. Chernikov */ 945d3a4f924SAlexander V. Chernikov 946d3a4f924SAlexander V. Chernikov /* 947d3a4f924SAlexander V. Chernikov * Get buffer size needed to list info for all tables. 948ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 949d3a4f924SAlexander V. Chernikov * Request: [ empty ], size = sizeof(ipfw_obj_lheader) 950d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ] 951d3a4f924SAlexander V. Chernikov * 952d3a4f924SAlexander V. Chernikov * Returns 0 on success 953f1220db8SAlexander V. Chernikov */ 954f1220db8SAlexander V. Chernikov int 9552d99a349SAlexander V. Chernikov ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 956f1220db8SAlexander V. Chernikov { 957f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 958f1220db8SAlexander V. Chernikov 9592d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 9602d99a349SAlexander V. Chernikov if (olh == NULL) 961d3a4f924SAlexander V. Chernikov return (EINVAL); 962d3a4f924SAlexander V. Chernikov 963f1220db8SAlexander V. Chernikov olh->size = sizeof(*olh); /* Make export_table store needed size */ 964f1220db8SAlexander V. Chernikov 965f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 9662d99a349SAlexander V. Chernikov export_tables(ch, olh, sd); 967f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 968f1220db8SAlexander V. Chernikov 9692d99a349SAlexander V. Chernikov return (0); 970f1220db8SAlexander V. Chernikov } 971f1220db8SAlexander V. Chernikov 972d3a4f924SAlexander V. Chernikov /* 973d3a4f924SAlexander V. Chernikov * Lists all tables currently available in kernel. 974ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 975d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 976d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ] 977d3a4f924SAlexander V. Chernikov * 978d3a4f924SAlexander V. Chernikov * Returns 0 on success 979d3a4f924SAlexander V. Chernikov */ 980f1220db8SAlexander V. Chernikov int 9812d99a349SAlexander V. Chernikov ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 982f1220db8SAlexander V. Chernikov { 983f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 984f1220db8SAlexander V. Chernikov int error; 985f1220db8SAlexander V. Chernikov 9862d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 9872d99a349SAlexander V. Chernikov if (olh == NULL) 988d3a4f924SAlexander V. Chernikov return (EINVAL); 98968394ec8SAlexander V. Chernikov if (sd->valsize < olh->size) 99068394ec8SAlexander V. Chernikov return (EINVAL); 991d3a4f924SAlexander V. Chernikov 992f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 9932d99a349SAlexander V. Chernikov error = export_tables(ch, olh, sd); 994f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 995f1220db8SAlexander V. Chernikov 996f1220db8SAlexander V. Chernikov return (error); 997f1220db8SAlexander V. Chernikov } 998f1220db8SAlexander V. Chernikov 999f1220db8SAlexander V. Chernikov /* 10002d99a349SAlexander V. Chernikov * Store table info to buffer provided by @sd. 1001ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 1002d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info(empty)] 1003d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ] 1004d3a4f924SAlexander V. Chernikov * 1005d3a4f924SAlexander V. Chernikov * Returns 0 on success. 1006d3a4f924SAlexander V. Chernikov */ 1007d3a4f924SAlexander V. Chernikov int 10082d99a349SAlexander V. Chernikov ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd) 1009d3a4f924SAlexander V. Chernikov { 1010d3a4f924SAlexander V. Chernikov struct _ipfw_obj_header *oh; 1011d3a4f924SAlexander V. Chernikov struct table_config *tc; 1012d3a4f924SAlexander V. Chernikov struct tid_info ti; 1013d3a4f924SAlexander V. Chernikov size_t sz; 1014d3a4f924SAlexander V. Chernikov 1015d3a4f924SAlexander V. Chernikov sz = sizeof(*oh) + sizeof(ipfw_xtable_info); 10162d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 10172d99a349SAlexander V. Chernikov if (oh == NULL) 1018d3a4f924SAlexander V. Chernikov return (EINVAL); 1019d3a4f924SAlexander V. Chernikov 1020d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 1021d3a4f924SAlexander V. Chernikov 1022d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 1023d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 1024d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1025d3a4f924SAlexander V. Chernikov return (ESRCH); 1026d3a4f924SAlexander V. Chernikov } 1027d3a4f924SAlexander V. Chernikov 1028ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, (ipfw_xtable_info *)(oh + 1)); 1029d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1030d3a4f924SAlexander V. Chernikov 10312d99a349SAlexander V. Chernikov return (0); 1032d3a4f924SAlexander V. Chernikov } 1033d3a4f924SAlexander V. Chernikov 1034f1220db8SAlexander V. Chernikov struct dump_args { 1035f1220db8SAlexander V. Chernikov struct table_info *ti; 1036f1220db8SAlexander V. Chernikov struct table_config *tc; 10372d99a349SAlexander V. Chernikov struct sockopt_data *sd; 1038f1220db8SAlexander V. Chernikov uint32_t cnt; 1039f1220db8SAlexander V. Chernikov uint16_t uidx; 104081d3153dSAlexander V. Chernikov int error; 10412d99a349SAlexander V. Chernikov ipfw_table_entry *ent; 10422d99a349SAlexander V. Chernikov uint32_t size; 104381d3153dSAlexander V. Chernikov ipfw_obj_tentry tent; 1044f1220db8SAlexander V. Chernikov }; 1045f1220db8SAlexander V. Chernikov 1046f1220db8SAlexander V. Chernikov int 10472d99a349SAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 10482d99a349SAlexander V. Chernikov struct sockopt_data *sd) 1049f1220db8SAlexander V. Chernikov { 1050d3a4f924SAlexander V. Chernikov int error; 1051d3a4f924SAlexander V. Chernikov 1052d3a4f924SAlexander V. Chernikov switch (op3->version) { 1053d3a4f924SAlexander V. Chernikov case 0: 10542d99a349SAlexander V. Chernikov error = ipfw_dump_table_v0(ch, sd); 1055d3a4f924SAlexander V. Chernikov break; 1056d3a4f924SAlexander V. Chernikov case 1: 10572d99a349SAlexander V. Chernikov error = ipfw_dump_table_v1(ch, sd); 1058d3a4f924SAlexander V. Chernikov break; 1059d3a4f924SAlexander V. Chernikov default: 1060d3a4f924SAlexander V. Chernikov error = ENOTSUP; 1061d3a4f924SAlexander V. Chernikov } 1062d3a4f924SAlexander V. Chernikov 1063d3a4f924SAlexander V. Chernikov return (error); 1064d3a4f924SAlexander V. Chernikov } 1065d3a4f924SAlexander V. Chernikov 1066d3a4f924SAlexander V. Chernikov /* 1067d3a4f924SAlexander V. Chernikov * Dumps all table data 1068ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 10692d99a349SAlexander V. Chernikov * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size 107081d3153dSAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ] 1071d3a4f924SAlexander V. Chernikov * 1072d3a4f924SAlexander V. Chernikov * Returns 0 on success 1073d3a4f924SAlexander V. Chernikov */ 1074d3a4f924SAlexander V. Chernikov static int 10752d99a349SAlexander V. Chernikov ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd) 1076d3a4f924SAlexander V. Chernikov { 1077f1220db8SAlexander V. Chernikov struct _ipfw_obj_header *oh; 1078f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1079f1220db8SAlexander V. Chernikov struct tid_info ti; 1080f1220db8SAlexander V. Chernikov struct table_config *tc; 1081f1220db8SAlexander V. Chernikov struct table_algo *ta; 1082f1220db8SAlexander V. Chernikov struct dump_args da; 1083d3a4f924SAlexander V. Chernikov uint32_t sz; 1084f1220db8SAlexander V. Chernikov 10852d99a349SAlexander V. Chernikov sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 10862d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 10872d99a349SAlexander V. Chernikov if (oh == NULL) 1088d3a4f924SAlexander V. Chernikov return (EINVAL); 1089d3a4f924SAlexander V. Chernikov 10902d99a349SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 1091d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 1092f1220db8SAlexander V. Chernikov 1093f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 1094f1220db8SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 1095f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1096f1220db8SAlexander V. Chernikov return (ESRCH); 1097f1220db8SAlexander V. Chernikov } 1098ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, i); 10992d99a349SAlexander V. Chernikov sz = tc->count; 11002d99a349SAlexander V. Chernikov 110181d3153dSAlexander V. Chernikov if (sd->valsize < sz + tc->count * sizeof(ipfw_obj_tentry)) { 11022d99a349SAlexander V. Chernikov 11032d99a349SAlexander V. Chernikov /* 11042d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 11052d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 11062d99a349SAlexander V. Chernikov * relevant table info including size, so we 11072d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 11082d99a349SAlexander V. Chernikov */ 1109f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 11102d99a349SAlexander V. Chernikov return (ENOMEM); 1111f1220db8SAlexander V. Chernikov } 1112f1220db8SAlexander V. Chernikov 1113f1220db8SAlexander V. Chernikov /* 1114f1220db8SAlexander V. Chernikov * Do the actual dump in eXtended format 1115f1220db8SAlexander V. Chernikov */ 1116d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 1117f1220db8SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 1118f1220db8SAlexander V. Chernikov da.tc = tc; 11192d99a349SAlexander V. Chernikov da.sd = sd; 1120f1220db8SAlexander V. Chernikov 1121f1220db8SAlexander V. Chernikov ta = tc->ta; 1122f1220db8SAlexander V. Chernikov 112381d3153dSAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_tentry, &da); 1124f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1125f1220db8SAlexander V. Chernikov 112681d3153dSAlexander V. Chernikov return (da.error); 1127f1220db8SAlexander V. Chernikov } 1128f1220db8SAlexander V. Chernikov 1129d3a4f924SAlexander V. Chernikov /* 1130d3a4f924SAlexander V. Chernikov * Dumps all table data 11312d99a349SAlexander V. Chernikov * Data layout (version 0)(legacy): 1132d3a4f924SAlexander V. Chernikov * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE() 1133d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_xtable ipfw_table_xentry x N ] 1134d3a4f924SAlexander V. Chernikov * 1135d3a4f924SAlexander V. Chernikov * Returns 0 on success 1136d3a4f924SAlexander V. Chernikov */ 1137d3a4f924SAlexander V. Chernikov static int 11382d99a349SAlexander V. Chernikov ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd) 1139d3a4f924SAlexander V. Chernikov { 1140d3a4f924SAlexander V. Chernikov ipfw_xtable *xtbl; 1141d3a4f924SAlexander V. Chernikov struct tid_info ti; 1142d3a4f924SAlexander V. Chernikov struct table_config *tc; 1143d3a4f924SAlexander V. Chernikov struct table_algo *ta; 1144d3a4f924SAlexander V. Chernikov struct dump_args da; 1145d3a4f924SAlexander V. Chernikov size_t sz; 1146d3a4f924SAlexander V. Chernikov 11472d99a349SAlexander V. Chernikov xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable)); 11482d99a349SAlexander V. Chernikov if (xtbl == NULL) 1149d3a4f924SAlexander V. Chernikov return (EINVAL); 1150d3a4f924SAlexander V. Chernikov 1151d3a4f924SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 1152d3a4f924SAlexander V. Chernikov ti.uidx = xtbl->tbl; 1153d3a4f924SAlexander V. Chernikov 1154d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 1155d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 1156d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1157d3a4f924SAlexander V. Chernikov return (0); 1158d3a4f924SAlexander V. Chernikov } 1159d3a4f924SAlexander V. Chernikov sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); 11602d99a349SAlexander V. Chernikov 11612d99a349SAlexander V. Chernikov xtbl->cnt = tc->count; 11622d99a349SAlexander V. Chernikov xtbl->size = sz; 11632d99a349SAlexander V. Chernikov xtbl->type = tc->no.type; 11642d99a349SAlexander V. Chernikov xtbl->tbl = ti.uidx; 11652d99a349SAlexander V. Chernikov 11662d99a349SAlexander V. Chernikov if (sd->valsize < sz) { 11672d99a349SAlexander V. Chernikov 11682d99a349SAlexander V. Chernikov /* 11692d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 11702d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 11712d99a349SAlexander V. Chernikov * relevant table info including size, so we 11722d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 11732d99a349SAlexander V. Chernikov */ 1174d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 11752d99a349SAlexander V. Chernikov return (ENOMEM); 1176d3a4f924SAlexander V. Chernikov } 1177d3a4f924SAlexander V. Chernikov 1178d3a4f924SAlexander V. Chernikov /* Do the actual dump in eXtended format */ 1179d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 1180d3a4f924SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 1181d3a4f924SAlexander V. Chernikov da.tc = tc; 11822d99a349SAlexander V. Chernikov da.sd = sd; 11832d99a349SAlexander V. Chernikov 1184d3a4f924SAlexander V. Chernikov ta = tc->ta; 1185d3a4f924SAlexander V. Chernikov 1186d3a4f924SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 1187d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1188d3a4f924SAlexander V. Chernikov 11892d99a349SAlexander V. Chernikov return (0); 1190d3a4f924SAlexander V. Chernikov } 1191d3a4f924SAlexander V. Chernikov 1192d3a4f924SAlexander V. Chernikov /* 11939490a627SAlexander V. Chernikov * Creates new table. 1194ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 11959490a627SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 11969490a627SAlexander V. Chernikov * 11979490a627SAlexander V. Chernikov * Returns 0 on success 11989490a627SAlexander V. Chernikov */ 11999490a627SAlexander V. Chernikov int 1200ac35ff17SAlexander V. Chernikov ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 1201ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 12029490a627SAlexander V. Chernikov { 12039490a627SAlexander V. Chernikov struct _ipfw_obj_header *oh; 12049490a627SAlexander V. Chernikov ipfw_xtable_info *i; 12059490a627SAlexander V. Chernikov char *tname, *aname; 12069490a627SAlexander V. Chernikov struct tid_info ti; 12079490a627SAlexander V. Chernikov struct namedobj_instance *ni; 12089490a627SAlexander V. Chernikov struct table_config *tc; 12099490a627SAlexander V. Chernikov 1210ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info)) 12119490a627SAlexander V. Chernikov return (EINVAL); 12129490a627SAlexander V. Chernikov 1213ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)sd->kbuf; 12149490a627SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 12159490a627SAlexander V. Chernikov 12169490a627SAlexander V. Chernikov /* 12179490a627SAlexander V. Chernikov * Verify user-supplied strings. 12182d99a349SAlexander V. Chernikov * Check for null-terminated/zero-length strings/ 12199490a627SAlexander V. Chernikov */ 1220ac35ff17SAlexander V. Chernikov tname = oh->ntlv.name; 12219490a627SAlexander V. Chernikov aname = i->algoname; 1222ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(tname) != 0 || 12239490a627SAlexander V. Chernikov strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname)) 12249490a627SAlexander V. Chernikov return (EINVAL); 12259490a627SAlexander V. Chernikov 12269490a627SAlexander V. Chernikov if (aname[0] == '\0') { 12279490a627SAlexander V. Chernikov /* Use default algorithm */ 12289490a627SAlexander V. Chernikov aname = NULL; 12299490a627SAlexander V. Chernikov } 12309490a627SAlexander V. Chernikov 12319490a627SAlexander V. Chernikov objheader_to_ti(oh, &ti); 1232ac35ff17SAlexander V. Chernikov ti.type = i->type; 12339490a627SAlexander V. Chernikov 12349490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 12359490a627SAlexander V. Chernikov 12369490a627SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 12379490a627SAlexander V. Chernikov if ((tc = find_table(ni, &ti)) != NULL) { 12389490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 12399490a627SAlexander V. Chernikov return (EEXIST); 12409490a627SAlexander V. Chernikov } 12419490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 12429490a627SAlexander V. Chernikov 12434c0c07a5SAlexander V. Chernikov return (create_table_internal(ch, &ti, aname, i)); 1244db785d31SAlexander V. Chernikov } 1245db785d31SAlexander V. Chernikov 1246db785d31SAlexander V. Chernikov /* 1247db785d31SAlexander V. Chernikov * Creates new table based on @ti and @aname. 1248db785d31SAlexander V. Chernikov * 1249db785d31SAlexander V. Chernikov * Relies on table name checking inside find_name_tlv() 1250db785d31SAlexander V. Chernikov * Assume @aname to be checked and valid. 1251db785d31SAlexander V. Chernikov * 1252db785d31SAlexander V. Chernikov * Returns 0 on success. 1253db785d31SAlexander V. Chernikov */ 1254db785d31SAlexander V. Chernikov static int 1255db785d31SAlexander V. Chernikov create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, 12564c0c07a5SAlexander V. Chernikov char *aname, ipfw_xtable_info *i) 1257db785d31SAlexander V. Chernikov { 1258db785d31SAlexander V. Chernikov struct namedobj_instance *ni; 1259db785d31SAlexander V. Chernikov struct table_config *tc; 1260db785d31SAlexander V. Chernikov struct table_algo *ta; 1261db785d31SAlexander V. Chernikov uint16_t kidx; 1262db785d31SAlexander V. Chernikov 1263db785d31SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1264db785d31SAlexander V. Chernikov 1265db785d31SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname); 12669490a627SAlexander V. Chernikov if (ta == NULL) 12679490a627SAlexander V. Chernikov return (ENOTSUP); 12689490a627SAlexander V. Chernikov 12694c0c07a5SAlexander V. Chernikov tc = alloc_table_config(ch, ti, ta, aname, i->tflags, i->vtype); 12704c0c07a5SAlexander V. Chernikov if (tc == NULL) 12719490a627SAlexander V. Chernikov return (ENOMEM); 12729490a627SAlexander V. Chernikov 12734c0c07a5SAlexander V. Chernikov tc->limit = i->limit; 12744c0c07a5SAlexander V. Chernikov 12759490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1276db785d31SAlexander V. Chernikov 1277db785d31SAlexander V. Chernikov /* Check if table has been already created */ 1278db785d31SAlexander V. Chernikov if (find_table(ni, ti) != NULL) { 1279db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1280db785d31SAlexander V. Chernikov free_table_config(ni, tc); 1281db785d31SAlexander V. Chernikov return (EEXIST); 1282db785d31SAlexander V. Chernikov } 1283db785d31SAlexander V. Chernikov 1284ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) { 12859490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1286db785d31SAlexander V. Chernikov printf("Unable to allocate table index." 1287db785d31SAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max"); 12889490a627SAlexander V. Chernikov free_table_config(ni, tc); 12899490a627SAlexander V. Chernikov return (EBUSY); 12909490a627SAlexander V. Chernikov } 12919490a627SAlexander V. Chernikov 12929490a627SAlexander V. Chernikov tc->no.kidx = kidx; 12939490a627SAlexander V. Chernikov 12949490a627SAlexander V. Chernikov IPFW_WLOCK(ch); 12959490a627SAlexander V. Chernikov link_table(ch, tc); 12969490a627SAlexander V. Chernikov IPFW_WUNLOCK(ch); 12979490a627SAlexander V. Chernikov 12989490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 12999490a627SAlexander V. Chernikov 13009490a627SAlexander V. Chernikov return (0); 13019490a627SAlexander V. Chernikov } 13029490a627SAlexander V. Chernikov 1303d3a4f924SAlexander V. Chernikov void 1304d3a4f924SAlexander V. Chernikov objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti) 1305d3a4f924SAlexander V. Chernikov { 1306d3a4f924SAlexander V. Chernikov 1307d3a4f924SAlexander V. Chernikov memset(ti, 0, sizeof(struct tid_info)); 130881d3153dSAlexander V. Chernikov ti->set = oh->ntlv.set; 1309d3a4f924SAlexander V. Chernikov ti->uidx = oh->idx; 1310d3a4f924SAlexander V. Chernikov ti->tlvs = &oh->ntlv; 1311d3a4f924SAlexander V. Chernikov ti->tlen = oh->ntlv.head.length; 1312d3a4f924SAlexander V. Chernikov } 1313d3a4f924SAlexander V. Chernikov 1314563b5ab1SAlexander V. Chernikov int 1315563b5ab1SAlexander V. Chernikov ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx, 1316563b5ab1SAlexander V. Chernikov struct sockopt_data *sd) 1317563b5ab1SAlexander V. Chernikov { 1318563b5ab1SAlexander V. Chernikov struct namedobj_instance *ni; 1319563b5ab1SAlexander V. Chernikov struct named_object *no; 1320563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1321563b5ab1SAlexander V. Chernikov 1322563b5ab1SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1323563b5ab1SAlexander V. Chernikov 1324ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 1325563b5ab1SAlexander V. Chernikov KASSERT(no != NULL, ("invalid table kidx passed")); 1326563b5ab1SAlexander V. Chernikov 1327563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 1328563b5ab1SAlexander V. Chernikov if (ntlv == NULL) 1329563b5ab1SAlexander V. Chernikov return (ENOMEM); 1330563b5ab1SAlexander V. Chernikov 1331563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 1332563b5ab1SAlexander V. Chernikov ntlv->head.length = sizeof(*ntlv); 1333563b5ab1SAlexander V. Chernikov ntlv->idx = no->kidx; 1334563b5ab1SAlexander V. Chernikov strlcpy(ntlv->name, no->name, sizeof(ntlv->name)); 1335563b5ab1SAlexander V. Chernikov 1336563b5ab1SAlexander V. Chernikov return (0); 1337563b5ab1SAlexander V. Chernikov } 1338563b5ab1SAlexander V. Chernikov 13399f7d47b0SAlexander V. Chernikov static void 1340ac35ff17SAlexander V. Chernikov export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 1341ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i) 13429f7d47b0SAlexander V. Chernikov { 1343ac35ff17SAlexander V. Chernikov struct table_info *ti; 13445f379342SAlexander V. Chernikov struct table_algo *ta; 13459f7d47b0SAlexander V. Chernikov 13469f7d47b0SAlexander V. Chernikov i->type = tc->no.type; 1347914bffb6SAlexander V. Chernikov i->tflags = tc->tflags; 1348ac35ff17SAlexander V. Chernikov i->vtype = tc->vtype; 13499f7d47b0SAlexander V. Chernikov i->set = tc->no.set; 13509f7d47b0SAlexander V. Chernikov i->kidx = tc->no.kidx; 13519f7d47b0SAlexander V. Chernikov i->refcnt = tc->no.refcnt; 13529f7d47b0SAlexander V. Chernikov i->count = tc->count; 13534c0c07a5SAlexander V. Chernikov i->limit = tc->limit; 135481d3153dSAlexander V. Chernikov i->size = tc->count * sizeof(ipfw_obj_tentry); 1355f1220db8SAlexander V. Chernikov i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 13569f7d47b0SAlexander V. Chernikov strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); 1357ac35ff17SAlexander V. Chernikov ti = KIDX_TO_TI(ch, tc->no.kidx); 13585f379342SAlexander V. Chernikov ta = tc->ta; 13595f379342SAlexander V. Chernikov if (ta->print_config != NULL) { 13605f379342SAlexander V. Chernikov /* Use algo function to print table config to string */ 13615f379342SAlexander V. Chernikov ta->print_config(tc->astate, ti, i->algoname, 1362ac35ff17SAlexander V. Chernikov sizeof(i->algoname)); 1363ac35ff17SAlexander V. Chernikov } else 13645f379342SAlexander V. Chernikov strlcpy(i->algoname, ta->name, sizeof(i->algoname)); 13655f379342SAlexander V. Chernikov /* Dump algo-specific data, if possible */ 13665f379342SAlexander V. Chernikov if (ta->dump_tinfo != NULL) { 13675f379342SAlexander V. Chernikov ta->dump_tinfo(tc->astate, ti, &i->ta_info); 13685f379342SAlexander V. Chernikov i->ta_info.flags |= IPFW_TATFLAGS_DATA; 13695f379342SAlexander V. Chernikov } 13709f7d47b0SAlexander V. Chernikov } 13719f7d47b0SAlexander V. Chernikov 1372ac35ff17SAlexander V. Chernikov struct dump_table_args { 1373ac35ff17SAlexander V. Chernikov struct ip_fw_chain *ch; 1374ac35ff17SAlexander V. Chernikov struct sockopt_data *sd; 1375ac35ff17SAlexander V. Chernikov }; 1376ac35ff17SAlexander V. Chernikov 13779f7d47b0SAlexander V. Chernikov static void 13789f7d47b0SAlexander V. Chernikov export_table_internal(struct namedobj_instance *ni, struct named_object *no, 13799f7d47b0SAlexander V. Chernikov void *arg) 13803b3a8eb9SGleb Smirnoff { 13819f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i; 1382ac35ff17SAlexander V. Chernikov struct dump_table_args *dta; 13833b3a8eb9SGleb Smirnoff 1384ac35ff17SAlexander V. Chernikov dta = (struct dump_table_args *)arg; 1385ac35ff17SAlexander V. Chernikov 1386ac35ff17SAlexander V. Chernikov i = (ipfw_xtable_info *)ipfw_get_sopt_space(dta->sd, sizeof(*i)); 138768394ec8SAlexander V. Chernikov KASSERT(i != 0, ("previously checked buffer is not enough")); 13889f7d47b0SAlexander V. Chernikov 1389ac35ff17SAlexander V. Chernikov export_table_info(dta->ch, (struct table_config *)no, i); 13909f7d47b0SAlexander V. Chernikov } 13919f7d47b0SAlexander V. Chernikov 1392f1220db8SAlexander V. Chernikov /* 1393f1220db8SAlexander V. Chernikov * Export all tables as ipfw_xtable_info structures to 13942d99a349SAlexander V. Chernikov * storage provided by @sd. 1395f1220db8SAlexander V. Chernikov * Returns 0 on success. 1396f1220db8SAlexander V. Chernikov */ 1397f1220db8SAlexander V. Chernikov static int 13982d99a349SAlexander V. Chernikov export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 13992d99a349SAlexander V. Chernikov struct sockopt_data *sd) 14009f7d47b0SAlexander V. Chernikov { 14019f7d47b0SAlexander V. Chernikov uint32_t size; 14029f7d47b0SAlexander V. Chernikov uint32_t count; 1403ac35ff17SAlexander V. Chernikov struct dump_table_args dta; 14049f7d47b0SAlexander V. Chernikov 14059f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 14069f7d47b0SAlexander V. Chernikov size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 14072d99a349SAlexander V. Chernikov 14082d99a349SAlexander V. Chernikov /* Fill in header regadless of buffer size */ 1409f1220db8SAlexander V. Chernikov olh->count = count; 1410f1220db8SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 14112d99a349SAlexander V. Chernikov 14122d99a349SAlexander V. Chernikov if (size > olh->size) { 14132d99a349SAlexander V. Chernikov olh->size = size; 14149f7d47b0SAlexander V. Chernikov return (ENOMEM); 1415f1220db8SAlexander V. Chernikov } 141668394ec8SAlexander V. Chernikov 14179f7d47b0SAlexander V. Chernikov olh->size = size; 14182d99a349SAlexander V. Chernikov 1419ac35ff17SAlexander V. Chernikov dta.ch = ch; 1420ac35ff17SAlexander V. Chernikov dta.sd = sd; 1421ac35ff17SAlexander V. Chernikov 1422ac35ff17SAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, &dta); 14239f7d47b0SAlexander V. Chernikov 14243b3a8eb9SGleb Smirnoff return (0); 14253b3a8eb9SGleb Smirnoff } 14263b3a8eb9SGleb Smirnoff 142781d3153dSAlexander V. Chernikov /* 142881d3153dSAlexander V. Chernikov * Legacy IP_FW_TABLE_GETSIZE handler 142981d3153dSAlexander V. Chernikov */ 14303b3a8eb9SGleb Smirnoff int 1431b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 14323b3a8eb9SGleb Smirnoff { 1433b074b7bbSAlexander V. Chernikov struct table_config *tc; 14343b3a8eb9SGleb Smirnoff 1435b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1436b074b7bbSAlexander V. Chernikov return (ESRCH); 14379f7d47b0SAlexander V. Chernikov *cnt = tc->count; 14383b3a8eb9SGleb Smirnoff return (0); 14393b3a8eb9SGleb Smirnoff } 14403b3a8eb9SGleb Smirnoff 14419f7d47b0SAlexander V. Chernikov 144281d3153dSAlexander V. Chernikov /* 144381d3153dSAlexander V. Chernikov * Legacy IP_FW_TABLE_XGETSIZE handler 144481d3153dSAlexander V. Chernikov */ 14459f7d47b0SAlexander V. Chernikov int 14469f7d47b0SAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 14473b3a8eb9SGleb Smirnoff { 14489f7d47b0SAlexander V. Chernikov struct table_config *tc; 14499f7d47b0SAlexander V. Chernikov 1450d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) { 1451d3a4f924SAlexander V. Chernikov *cnt = 0; 14529f7d47b0SAlexander V. Chernikov return (0); /* 'table all list' requires success */ 1453d3a4f924SAlexander V. Chernikov } 14549f7d47b0SAlexander V. Chernikov *cnt = tc->count * sizeof(ipfw_table_xentry); 14559f7d47b0SAlexander V. Chernikov if (tc->count > 0) 14569f7d47b0SAlexander V. Chernikov *cnt += sizeof(ipfw_xtable); 14579f7d47b0SAlexander V. Chernikov return (0); 14589f7d47b0SAlexander V. Chernikov } 14599f7d47b0SAlexander V. Chernikov 14609f7d47b0SAlexander V. Chernikov static int 14619f7d47b0SAlexander V. Chernikov dump_table_entry(void *e, void *arg) 14629f7d47b0SAlexander V. Chernikov { 14639f7d47b0SAlexander V. Chernikov struct dump_args *da; 14649f7d47b0SAlexander V. Chernikov struct table_config *tc; 14659f7d47b0SAlexander V. Chernikov struct table_algo *ta; 14663b3a8eb9SGleb Smirnoff ipfw_table_entry *ent; 146781d3153dSAlexander V. Chernikov int error; 14683b3a8eb9SGleb Smirnoff 14699f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 14709f7d47b0SAlexander V. Chernikov 14719f7d47b0SAlexander V. Chernikov tc = da->tc; 14729f7d47b0SAlexander V. Chernikov ta = tc->ta; 14739f7d47b0SAlexander V. Chernikov 14749f7d47b0SAlexander V. Chernikov /* Out of memory, returning */ 1475f1220db8SAlexander V. Chernikov if (da->cnt == da->size) 14763b3a8eb9SGleb Smirnoff return (1); 1477f1220db8SAlexander V. Chernikov ent = da->ent++; 1478f1220db8SAlexander V. Chernikov ent->tbl = da->uidx; 1479f1220db8SAlexander V. Chernikov da->cnt++; 14809f7d47b0SAlexander V. Chernikov 148181d3153dSAlexander V. Chernikov error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent); 148281d3153dSAlexander V. Chernikov if (error != 0) 148381d3153dSAlexander V. Chernikov return (error); 148481d3153dSAlexander V. Chernikov 148581d3153dSAlexander V. Chernikov ent->addr = da->tent.k.addr.s_addr; 148681d3153dSAlexander V. Chernikov ent->masklen = da->tent.masklen; 148781d3153dSAlexander V. Chernikov ent->value = da->tent.value; 148881d3153dSAlexander V. Chernikov 148981d3153dSAlexander V. Chernikov return (0); 14903b3a8eb9SGleb Smirnoff } 14913b3a8eb9SGleb Smirnoff 1492f1220db8SAlexander V. Chernikov /* 1493f1220db8SAlexander V. Chernikov * Dumps table in pre-8.1 legacy format. 1494f1220db8SAlexander V. Chernikov */ 14953b3a8eb9SGleb Smirnoff int 1496f1220db8SAlexander V. Chernikov ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti, 1497f1220db8SAlexander V. Chernikov ipfw_table *tbl) 14983b3a8eb9SGleb Smirnoff { 1499b074b7bbSAlexander V. Chernikov struct table_config *tc; 15009f7d47b0SAlexander V. Chernikov struct table_algo *ta; 15019f7d47b0SAlexander V. Chernikov struct dump_args da; 15023b3a8eb9SGleb Smirnoff 15033b3a8eb9SGleb Smirnoff tbl->cnt = 0; 15043b3a8eb9SGleb Smirnoff 1505b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1506b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 15079f7d47b0SAlexander V. Chernikov 15089f7d47b0SAlexander V. Chernikov ta = tc->ta; 15099f7d47b0SAlexander V. Chernikov 151081d3153dSAlexander V. Chernikov /* This dump format supports IPv4 only */ 151181d3153dSAlexander V. Chernikov if (tc->no.type != IPFW_TABLE_CIDR) 151281d3153dSAlexander V. Chernikov return (0); 15139f7d47b0SAlexander V. Chernikov 1514d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 15159f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 15169f7d47b0SAlexander V. Chernikov da.tc = tc; 1517f1220db8SAlexander V. Chernikov da.ent = &tbl->ent[0]; 1518f1220db8SAlexander V. Chernikov da.size = tbl->size; 15199f7d47b0SAlexander V. Chernikov 15209f7d47b0SAlexander V. Chernikov tbl->cnt = 0; 15219f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_entry, &da); 1522f1220db8SAlexander V. Chernikov tbl->cnt = da.cnt; 15239f7d47b0SAlexander V. Chernikov 15243b3a8eb9SGleb Smirnoff return (0); 15253b3a8eb9SGleb Smirnoff } 15263b3a8eb9SGleb Smirnoff 15279490a627SAlexander V. Chernikov /* 152881d3153dSAlexander V. Chernikov * Dumps table entry in eXtended format (v1)(current). 152981d3153dSAlexander V. Chernikov */ 153081d3153dSAlexander V. Chernikov static int 153181d3153dSAlexander V. Chernikov dump_table_tentry(void *e, void *arg) 153281d3153dSAlexander V. Chernikov { 153381d3153dSAlexander V. Chernikov struct dump_args *da; 153481d3153dSAlexander V. Chernikov struct table_config *tc; 153581d3153dSAlexander V. Chernikov struct table_algo *ta; 153681d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 153781d3153dSAlexander V. Chernikov 153881d3153dSAlexander V. Chernikov da = (struct dump_args *)arg; 153981d3153dSAlexander V. Chernikov 154081d3153dSAlexander V. Chernikov tc = da->tc; 154181d3153dSAlexander V. Chernikov ta = tc->ta; 154281d3153dSAlexander V. Chernikov 154381d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent)); 154481d3153dSAlexander V. Chernikov /* Out of memory, returning */ 154581d3153dSAlexander V. Chernikov if (tent == NULL) { 154681d3153dSAlexander V. Chernikov da->error = ENOMEM; 154781d3153dSAlexander V. Chernikov return (1); 154881d3153dSAlexander V. Chernikov } 154981d3153dSAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 155081d3153dSAlexander V. Chernikov tent->idx = da->uidx; 155181d3153dSAlexander V. Chernikov 155281d3153dSAlexander V. Chernikov return (ta->dump_tentry(tc->astate, da->ti, e, tent)); 155381d3153dSAlexander V. Chernikov } 155481d3153dSAlexander V. Chernikov 155581d3153dSAlexander V. Chernikov /* 155681d3153dSAlexander V. Chernikov * Dumps table entry in eXtended format (v0). 15579490a627SAlexander V. Chernikov */ 15583b3a8eb9SGleb Smirnoff static int 15599f7d47b0SAlexander V. Chernikov dump_table_xentry(void *e, void *arg) 15603b3a8eb9SGleb Smirnoff { 15619f7d47b0SAlexander V. Chernikov struct dump_args *da; 15629f7d47b0SAlexander V. Chernikov struct table_config *tc; 15639f7d47b0SAlexander V. Chernikov struct table_algo *ta; 15643b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 156581d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 156681d3153dSAlexander V. Chernikov int error; 15673b3a8eb9SGleb Smirnoff 15689f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 15699f7d47b0SAlexander V. Chernikov 15709f7d47b0SAlexander V. Chernikov tc = da->tc; 15719f7d47b0SAlexander V. Chernikov ta = tc->ta; 15729f7d47b0SAlexander V. Chernikov 15732d99a349SAlexander V. Chernikov xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent)); 15743b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 15752d99a349SAlexander V. Chernikov if (xent == NULL) 15763b3a8eb9SGleb Smirnoff return (1); 15773b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 1578f1220db8SAlexander V. Chernikov xent->tbl = da->uidx; 15799f7d47b0SAlexander V. Chernikov 158081d3153dSAlexander V. Chernikov memset(&da->tent, 0, sizeof(da->tent)); 158181d3153dSAlexander V. Chernikov tent = &da->tent; 158281d3153dSAlexander V. Chernikov error = ta->dump_tentry(tc->astate, da->ti, e, tent); 158381d3153dSAlexander V. Chernikov if (error != 0) 158481d3153dSAlexander V. Chernikov return (error); 158581d3153dSAlexander V. Chernikov 158681d3153dSAlexander V. Chernikov /* Convert current format to previous one */ 158781d3153dSAlexander V. Chernikov xent->masklen = tent->masklen; 158881d3153dSAlexander V. Chernikov xent->value = tent->value; 158981d3153dSAlexander V. Chernikov /* Apply some hacks */ 159081d3153dSAlexander V. Chernikov if (tc->no.type == IPFW_TABLE_CIDR && tent->subtype == AF_INET) { 159181d3153dSAlexander V. Chernikov xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr; 159281d3153dSAlexander V. Chernikov xent->flags = IPFW_TCF_INET; 159381d3153dSAlexander V. Chernikov } else 159481d3153dSAlexander V. Chernikov memcpy(&xent->k, &tent->k, sizeof(xent->k)); 159581d3153dSAlexander V. Chernikov 159681d3153dSAlexander V. Chernikov return (0); 15979f7d47b0SAlexander V. Chernikov } 15989f7d47b0SAlexander V. Chernikov 15999f7d47b0SAlexander V. Chernikov /* 16009f7d47b0SAlexander V. Chernikov * Table algorithms 16019f7d47b0SAlexander V. Chernikov */ 16023b3a8eb9SGleb Smirnoff 16039f7d47b0SAlexander V. Chernikov /* 16049490a627SAlexander V. Chernikov * Finds algoritm by index, table type or supplied name 16059f7d47b0SAlexander V. Chernikov */ 16069f7d47b0SAlexander V. Chernikov static struct table_algo * 16079490a627SAlexander V. Chernikov find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name) 16089f7d47b0SAlexander V. Chernikov { 16099490a627SAlexander V. Chernikov int i, l; 16109490a627SAlexander V. Chernikov struct table_algo *ta; 16119f7d47b0SAlexander V. Chernikov 161257a1cf95SAlexander V. Chernikov if (ti->type > IPFW_TABLE_MAXTYPE) 161357a1cf95SAlexander V. Chernikov return (NULL); 161457a1cf95SAlexander V. Chernikov 16159f7d47b0SAlexander V. Chernikov /* Search by index */ 16169f7d47b0SAlexander V. Chernikov if (ti->atype != 0) { 16179f7d47b0SAlexander V. Chernikov if (ti->atype > tcfg->algo_count) 16189f7d47b0SAlexander V. Chernikov return (NULL); 16199f7d47b0SAlexander V. Chernikov return (tcfg->algo[ti->atype]); 16209f7d47b0SAlexander V. Chernikov } 16219f7d47b0SAlexander V. Chernikov 16229490a627SAlexander V. Chernikov /* Search by name if supplied */ 16239490a627SAlexander V. Chernikov if (name != NULL) { 16249490a627SAlexander V. Chernikov /* TODO: better search */ 16259490a627SAlexander V. Chernikov for (i = 1; i <= tcfg->algo_count; i++) { 16269490a627SAlexander V. Chernikov ta = tcfg->algo[i]; 16279490a627SAlexander V. Chernikov 16289490a627SAlexander V. Chernikov /* 16299490a627SAlexander V. Chernikov * One can supply additional algorithm 16309490a627SAlexander V. Chernikov * parameters so we compare only the first word 16319490a627SAlexander V. Chernikov * of supplied name: 16329490a627SAlexander V. Chernikov * 'hash_cidr hsize=32' 16339490a627SAlexander V. Chernikov * '^^^^^^^^^' 16349490a627SAlexander V. Chernikov * 16359490a627SAlexander V. Chernikov */ 16369490a627SAlexander V. Chernikov l = strlen(ta->name); 16379490a627SAlexander V. Chernikov if (strncmp(name, ta->name, l) == 0) { 16389490a627SAlexander V. Chernikov if (name[l] == '\0' || name[l] == ' ') 16399490a627SAlexander V. Chernikov return (ta); 16409490a627SAlexander V. Chernikov } 16419490a627SAlexander V. Chernikov } 16429490a627SAlexander V. Chernikov 16439490a627SAlexander V. Chernikov return (NULL); 16449490a627SAlexander V. Chernikov } 16459490a627SAlexander V. Chernikov 164657a1cf95SAlexander V. Chernikov /* Return default algorithm for given type if set */ 164757a1cf95SAlexander V. Chernikov return (tcfg->def_algo[ti->type]); 16483b3a8eb9SGleb Smirnoff } 16493b3a8eb9SGleb Smirnoff 1650b6ee846eSAlexander V. Chernikov /* 1651b6ee846eSAlexander V. Chernikov * Register new table algo @ta. 1652b6ee846eSAlexander V. Chernikov * Stores algo id iside @idx.<F2> 1653b6ee846eSAlexander V. Chernikov * 1654b6ee846eSAlexander V. Chernikov * Returns 0 on success. 1655b6ee846eSAlexander V. Chernikov */ 16560b565ac0SAlexander V. Chernikov int 16570b565ac0SAlexander V. Chernikov ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta, size_t size, 16580b565ac0SAlexander V. Chernikov int *idx) 16593b3a8eb9SGleb Smirnoff { 16609f7d47b0SAlexander V. Chernikov struct tables_config *tcfg; 16610b565ac0SAlexander V. Chernikov struct table_algo *ta_new; 1662b6ee846eSAlexander V. Chernikov size_t sz; 16630b565ac0SAlexander V. Chernikov 16640b565ac0SAlexander V. Chernikov if (size > sizeof(struct table_algo)) 16650b565ac0SAlexander V. Chernikov return (EINVAL); 16660b565ac0SAlexander V. Chernikov 1667b6ee846eSAlexander V. Chernikov /* Check for the required on-stack size for add/del */ 1668b6ee846eSAlexander V. Chernikov sz = roundup2(ta->ta_buf_size, sizeof(void *)); 1669b6ee846eSAlexander V. Chernikov if (sz > TA_BUF_SZ) 1670b6ee846eSAlexander V. Chernikov return (EINVAL); 1671b6ee846eSAlexander V. Chernikov 167257a1cf95SAlexander V. Chernikov KASSERT(ta->type >= IPFW_TABLE_MAXTYPE,("Increase IPFW_TABLE_MAXTYPE")); 167357a1cf95SAlexander V. Chernikov 16740b565ac0SAlexander V. Chernikov ta_new = malloc(sizeof(struct table_algo), M_IPFW, M_WAITOK | M_ZERO); 16750b565ac0SAlexander V. Chernikov memcpy(ta_new, ta, size); 16763b3a8eb9SGleb Smirnoff 16779f7d47b0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 1678b074b7bbSAlexander V. Chernikov 16799f7d47b0SAlexander V. Chernikov KASSERT(tcfg->algo_count < 255, ("Increase algo array size")); 16809f7d47b0SAlexander V. Chernikov 16810b565ac0SAlexander V. Chernikov tcfg->algo[++tcfg->algo_count] = ta_new; 16820b565ac0SAlexander V. Chernikov ta_new->idx = tcfg->algo_count; 16830b565ac0SAlexander V. Chernikov 168457a1cf95SAlexander V. Chernikov /* Set algorithm as default one for given type */ 168557a1cf95SAlexander V. Chernikov if ((ta_new->flags & TA_FLAG_DEFAULT) != 0 && 168657a1cf95SAlexander V. Chernikov tcfg->def_algo[ta_new->type] == NULL) 168757a1cf95SAlexander V. Chernikov tcfg->def_algo[ta_new->type] = ta_new; 168857a1cf95SAlexander V. Chernikov 16890b565ac0SAlexander V. Chernikov *idx = ta_new->idx; 16900b565ac0SAlexander V. Chernikov 16910b565ac0SAlexander V. Chernikov return (0); 16920b565ac0SAlexander V. Chernikov } 16930b565ac0SAlexander V. Chernikov 1694b6ee846eSAlexander V. Chernikov /* 1695b6ee846eSAlexander V. Chernikov * Unregisters table algo using @idx as id. 1696b6ee846eSAlexander V. Chernikov */ 16970b565ac0SAlexander V. Chernikov void 16980b565ac0SAlexander V. Chernikov ipfw_del_table_algo(struct ip_fw_chain *ch, int idx) 16990b565ac0SAlexander V. Chernikov { 17000b565ac0SAlexander V. Chernikov struct tables_config *tcfg; 17010b565ac0SAlexander V. Chernikov struct table_algo *ta; 17020b565ac0SAlexander V. Chernikov 17030b565ac0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 17040b565ac0SAlexander V. Chernikov 1705b6ee846eSAlexander V. Chernikov KASSERT(idx <= tcfg->algo_count, ("algo idx %d out of range 1..%d", 1706b6ee846eSAlexander V. Chernikov idx, tcfg->algo_count)); 17070b565ac0SAlexander V. Chernikov 17080b565ac0SAlexander V. Chernikov ta = tcfg->algo[idx]; 17090b565ac0SAlexander V. Chernikov KASSERT(ta != NULL, ("algo idx %d is NULL", idx)); 171057a1cf95SAlexander V. Chernikov 171157a1cf95SAlexander V. Chernikov if (tcfg->def_algo[ta->type] == ta) 171257a1cf95SAlexander V. Chernikov tcfg->def_algo[ta->type] = NULL; 171357a1cf95SAlexander V. Chernikov 17140b565ac0SAlexander V. Chernikov free(ta, M_IPFW); 17153b3a8eb9SGleb Smirnoff } 17163b3a8eb9SGleb Smirnoff 17179d099b4fSAlexander V. Chernikov /* 17189d099b4fSAlexander V. Chernikov * Lists all table algorithms currently available. 17199d099b4fSAlexander V. Chernikov * Data layout (v0)(current): 17209d099b4fSAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 17219d099b4fSAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_ta_info x N ] 17229d099b4fSAlexander V. Chernikov * 17239d099b4fSAlexander V. Chernikov * Returns 0 on success 17249d099b4fSAlexander V. Chernikov */ 17259d099b4fSAlexander V. Chernikov int 17269d099b4fSAlexander V. Chernikov ipfw_list_table_algo(struct ip_fw_chain *ch, struct sockopt_data *sd) 17279d099b4fSAlexander V. Chernikov { 17289d099b4fSAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 17299d099b4fSAlexander V. Chernikov struct tables_config *tcfg; 17309d099b4fSAlexander V. Chernikov ipfw_ta_info *i; 17319d099b4fSAlexander V. Chernikov struct table_algo *ta; 17329d099b4fSAlexander V. Chernikov uint32_t count, n, size; 17339d099b4fSAlexander V. Chernikov 17349d099b4fSAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 17359d099b4fSAlexander V. Chernikov if (olh == NULL) 17369d099b4fSAlexander V. Chernikov return (EINVAL); 17379d099b4fSAlexander V. Chernikov if (sd->valsize < olh->size) 17389d099b4fSAlexander V. Chernikov return (EINVAL); 17399d099b4fSAlexander V. Chernikov 17409d099b4fSAlexander V. Chernikov IPFW_UH_RLOCK(ch); 17419d099b4fSAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 17429d099b4fSAlexander V. Chernikov count = tcfg->algo_count; 17439d099b4fSAlexander V. Chernikov size = count * sizeof(ipfw_ta_info) + sizeof(ipfw_obj_lheader); 17449d099b4fSAlexander V. Chernikov 17459d099b4fSAlexander V. Chernikov /* Fill in header regadless of buffer size */ 17469d099b4fSAlexander V. Chernikov olh->count = count; 17479d099b4fSAlexander V. Chernikov olh->objsize = sizeof(ipfw_ta_info); 17489d099b4fSAlexander V. Chernikov 17499d099b4fSAlexander V. Chernikov if (size > olh->size) { 17509d099b4fSAlexander V. Chernikov olh->size = size; 17519d099b4fSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 17529d099b4fSAlexander V. Chernikov return (ENOMEM); 17539d099b4fSAlexander V. Chernikov } 17549d099b4fSAlexander V. Chernikov olh->size = size; 17559d099b4fSAlexander V. Chernikov 17569d099b4fSAlexander V. Chernikov for (n = 1; n <= count; n++) { 17579d099b4fSAlexander V. Chernikov i = (ipfw_ta_info *)ipfw_get_sopt_space(sd, sizeof(*i)); 17589d099b4fSAlexander V. Chernikov KASSERT(i != 0, ("previously checked buffer is not enough")); 17599d099b4fSAlexander V. Chernikov ta = tcfg->algo[n]; 17609d099b4fSAlexander V. Chernikov strlcpy(i->algoname, ta->name, sizeof(i->algoname)); 17619d099b4fSAlexander V. Chernikov i->type = ta->type; 17629d099b4fSAlexander V. Chernikov i->refcnt = ta->refcnt; 17639d099b4fSAlexander V. Chernikov } 17649d099b4fSAlexander V. Chernikov 17659d099b4fSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 17669d099b4fSAlexander V. Chernikov 17679d099b4fSAlexander V. Chernikov return (0); 17689d099b4fSAlexander V. Chernikov } 17699d099b4fSAlexander V. Chernikov 17709f7d47b0SAlexander V. Chernikov 1771b074b7bbSAlexander V. Chernikov /* 1772b074b7bbSAlexander V. Chernikov * Tables rewriting code 1773b074b7bbSAlexander V. Chernikov * 1774b074b7bbSAlexander V. Chernikov */ 1775b074b7bbSAlexander V. Chernikov 1776b074b7bbSAlexander V. Chernikov /* 1777b074b7bbSAlexander V. Chernikov * Determine table number and lookup type for @cmd. 1778b074b7bbSAlexander V. Chernikov * Fill @tbl and @type with appropriate values. 1779b074b7bbSAlexander V. Chernikov * Returns 0 for relevant opcodes, 1 otherwise. 1780b074b7bbSAlexander V. Chernikov */ 1781b074b7bbSAlexander V. Chernikov static int 1782b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 1783b074b7bbSAlexander V. Chernikov { 1784b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1785b074b7bbSAlexander V. Chernikov int skip; 1786b074b7bbSAlexander V. Chernikov uint16_t v; 1787b074b7bbSAlexander V. Chernikov 1788b074b7bbSAlexander V. Chernikov skip = 1; 1789b074b7bbSAlexander V. Chernikov 1790b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1791b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1792b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1793b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1794b074b7bbSAlexander V. Chernikov *puidx = cmd->arg1; 1795b074b7bbSAlexander V. Chernikov /* Assume CIDR by default */ 1796b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 1797b074b7bbSAlexander V. Chernikov skip = 0; 1798b074b7bbSAlexander V. Chernikov 1799b074b7bbSAlexander V. Chernikov if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { 1800b074b7bbSAlexander V. Chernikov /* 1801b074b7bbSAlexander V. Chernikov * generic lookup. The key must be 1802b074b7bbSAlexander V. Chernikov * in 32bit big-endian format. 1803b074b7bbSAlexander V. Chernikov */ 1804b074b7bbSAlexander V. Chernikov v = ((ipfw_insn_u32 *)cmd)->d[1]; 1805b074b7bbSAlexander V. Chernikov switch (v) { 1806b074b7bbSAlexander V. Chernikov case 0: 1807b074b7bbSAlexander V. Chernikov case 1: 1808b074b7bbSAlexander V. Chernikov /* IPv4 src/dst */ 1809b074b7bbSAlexander V. Chernikov break; 1810b074b7bbSAlexander V. Chernikov case 2: 1811b074b7bbSAlexander V. Chernikov case 3: 1812b074b7bbSAlexander V. Chernikov /* src/dst port */ 1813b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1814b074b7bbSAlexander V. Chernikov break; 1815b074b7bbSAlexander V. Chernikov case 4: 1816b074b7bbSAlexander V. Chernikov /* uid/gid */ 1817b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1818b23d5de9SAlexander V. Chernikov break; 1819b074b7bbSAlexander V. Chernikov case 5: 1820b074b7bbSAlexander V. Chernikov /* jid */ 1821b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1822b23d5de9SAlexander V. Chernikov break; 1823b074b7bbSAlexander V. Chernikov case 6: 1824b074b7bbSAlexander V. Chernikov /* dscp */ 1825b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1826b074b7bbSAlexander V. Chernikov break; 1827b074b7bbSAlexander V. Chernikov } 1828b074b7bbSAlexander V. Chernikov } 1829b074b7bbSAlexander V. Chernikov break; 1830b074b7bbSAlexander V. Chernikov case O_XMIT: 1831b074b7bbSAlexander V. Chernikov case O_RECV: 1832b074b7bbSAlexander V. Chernikov case O_VIA: 1833b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1834b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1835b074b7bbSAlexander V. Chernikov if (cmdif->name[0] != '\1') 1836b074b7bbSAlexander V. Chernikov break; 1837b074b7bbSAlexander V. Chernikov 1838b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 1839b074b7bbSAlexander V. Chernikov *puidx = cmdif->p.glob; 1840b074b7bbSAlexander V. Chernikov skip = 0; 1841b074b7bbSAlexander V. Chernikov break; 1842914bffb6SAlexander V. Chernikov case O_IP_FLOW_LOOKUP: 1843914bffb6SAlexander V. Chernikov *puidx = cmd->arg1; 1844914bffb6SAlexander V. Chernikov *ptype = IPFW_TABLE_FLOW; 1845914bffb6SAlexander V. Chernikov skip = 0; 1846914bffb6SAlexander V. Chernikov break; 1847b074b7bbSAlexander V. Chernikov } 1848b074b7bbSAlexander V. Chernikov 1849b074b7bbSAlexander V. Chernikov return (skip); 1850b074b7bbSAlexander V. Chernikov } 1851b074b7bbSAlexander V. Chernikov 1852b074b7bbSAlexander V. Chernikov /* 1853b074b7bbSAlexander V. Chernikov * Sets new table value for given opcode. 1854b074b7bbSAlexander V. Chernikov * Assume the same opcodes as classify_table_opcode() 1855b074b7bbSAlexander V. Chernikov */ 1856b074b7bbSAlexander V. Chernikov static void 1857b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx) 1858b074b7bbSAlexander V. Chernikov { 1859b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1860b074b7bbSAlexander V. Chernikov 1861b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1862b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1863b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1864b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1865b074b7bbSAlexander V. Chernikov cmd->arg1 = idx; 1866b074b7bbSAlexander V. Chernikov break; 1867b074b7bbSAlexander V. Chernikov case O_XMIT: 1868b074b7bbSAlexander V. Chernikov case O_RECV: 1869b074b7bbSAlexander V. Chernikov case O_VIA: 1870b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1871b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1872b074b7bbSAlexander V. Chernikov cmdif->p.glob = idx; 1873b074b7bbSAlexander V. Chernikov break; 1874914bffb6SAlexander V. Chernikov case O_IP_FLOW_LOOKUP: 1875914bffb6SAlexander V. Chernikov cmd->arg1 = idx; 1876914bffb6SAlexander V. Chernikov break; 1877b074b7bbSAlexander V. Chernikov } 1878b074b7bbSAlexander V. Chernikov } 1879b074b7bbSAlexander V. Chernikov 1880ac35ff17SAlexander V. Chernikov /* 1881ac35ff17SAlexander V. Chernikov * Checks table name for validity. 1882ac35ff17SAlexander V. Chernikov * Enforce basic length checks, the rest 1883ac35ff17SAlexander V. Chernikov * should be done in userland. 1884ac35ff17SAlexander V. Chernikov * 1885ac35ff17SAlexander V. Chernikov * Returns 0 if name is considered valid. 1886ac35ff17SAlexander V. Chernikov */ 1887ac35ff17SAlexander V. Chernikov int 1888ac35ff17SAlexander V. Chernikov ipfw_check_table_name(char *name) 1889ac35ff17SAlexander V. Chernikov { 1890ac35ff17SAlexander V. Chernikov int nsize; 1891ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv = NULL; 1892ac35ff17SAlexander V. Chernikov 1893ac35ff17SAlexander V. Chernikov nsize = sizeof(ntlv->name); 1894ac35ff17SAlexander V. Chernikov 1895ac35ff17SAlexander V. Chernikov if (strnlen(name, nsize) == nsize) 1896ac35ff17SAlexander V. Chernikov return (EINVAL); 1897ac35ff17SAlexander V. Chernikov 1898ac35ff17SAlexander V. Chernikov if (name[0] == '\0') 1899ac35ff17SAlexander V. Chernikov return (EINVAL); 1900ac35ff17SAlexander V. Chernikov 1901ac35ff17SAlexander V. Chernikov /* 1902ac35ff17SAlexander V. Chernikov * TODO: do some more complicated checks 1903ac35ff17SAlexander V. Chernikov */ 1904ac35ff17SAlexander V. Chernikov 1905ac35ff17SAlexander V. Chernikov return (0); 1906ac35ff17SAlexander V. Chernikov } 1907ac35ff17SAlexander V. Chernikov 1908ac35ff17SAlexander V. Chernikov /* 1909ac35ff17SAlexander V. Chernikov * Find tablename TLV by @uid. 1910ac35ff17SAlexander V. Chernikov * Check @tlvs for valid data inside. 1911ac35ff17SAlexander V. Chernikov * 1912ac35ff17SAlexander V. Chernikov * Returns pointer to found TLV or NULL. 1913ac35ff17SAlexander V. Chernikov */ 1914ac35ff17SAlexander V. Chernikov static ipfw_obj_ntlv * 1915b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx) 1916b074b7bbSAlexander V. Chernikov { 19179f7d47b0SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1918b074b7bbSAlexander V. Chernikov uintptr_t pa, pe; 1919b074b7bbSAlexander V. Chernikov int l; 1920b074b7bbSAlexander V. Chernikov 1921b074b7bbSAlexander V. Chernikov pa = (uintptr_t)tlvs; 1922b074b7bbSAlexander V. Chernikov pe = pa + len; 1923b074b7bbSAlexander V. Chernikov l = 0; 1924b074b7bbSAlexander V. Chernikov for (; pa < pe; pa += l) { 19259f7d47b0SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)pa; 1926b074b7bbSAlexander V. Chernikov l = ntlv->head.length; 1927ac35ff17SAlexander V. Chernikov 1928ac35ff17SAlexander V. Chernikov if (l != sizeof(*ntlv)) 1929ac35ff17SAlexander V. Chernikov return (NULL); 1930ac35ff17SAlexander V. Chernikov 1931563b5ab1SAlexander V. Chernikov if (ntlv->head.type != IPFW_TLV_TBL_NAME) 1932b074b7bbSAlexander V. Chernikov continue; 1933ac35ff17SAlexander V. Chernikov 1934b074b7bbSAlexander V. Chernikov if (ntlv->idx != uidx) 1935b074b7bbSAlexander V. Chernikov continue; 1936b074b7bbSAlexander V. Chernikov 1937ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(ntlv->name) != 0) 1938ac35ff17SAlexander V. Chernikov return (NULL); 1939ac35ff17SAlexander V. Chernikov 1940ac35ff17SAlexander V. Chernikov return (ntlv); 1941b074b7bbSAlexander V. Chernikov } 1942b074b7bbSAlexander V. Chernikov 1943b074b7bbSAlexander V. Chernikov return (NULL); 1944b074b7bbSAlexander V. Chernikov } 1945b074b7bbSAlexander V. Chernikov 1946ac35ff17SAlexander V. Chernikov /* 1947ac35ff17SAlexander V. Chernikov * Finds table config based on either legacy index 1948ac35ff17SAlexander V. Chernikov * or name in ntlv. 1949ac35ff17SAlexander V. Chernikov * Note @ti structure contains unchecked data from userland. 1950ac35ff17SAlexander V. Chernikov * 1951ac35ff17SAlexander V. Chernikov * Returns pointer to table_config or NULL. 1952ac35ff17SAlexander V. Chernikov */ 1953b074b7bbSAlexander V. Chernikov static struct table_config * 1954b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti) 1955b074b7bbSAlexander V. Chernikov { 1956b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1957b074b7bbSAlexander V. Chernikov struct named_object *no; 1958ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1959ac35ff17SAlexander V. Chernikov uint32_t set; 1960b074b7bbSAlexander V. Chernikov 1961b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1962ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1963ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1964b074b7bbSAlexander V. Chernikov return (NULL); 1965ac35ff17SAlexander V. Chernikov name = ntlv->name; 1966ac35ff17SAlexander V. Chernikov set = ntlv->set; 1967b074b7bbSAlexander V. Chernikov } else { 1968b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1969b074b7bbSAlexander V. Chernikov name = bname; 1970ac35ff17SAlexander V. Chernikov set = 0; 1971b074b7bbSAlexander V. Chernikov } 1972b074b7bbSAlexander V. Chernikov 1973ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_name(ni, set, name); 1974b074b7bbSAlexander V. Chernikov 1975b074b7bbSAlexander V. Chernikov return ((struct table_config *)no); 1976b074b7bbSAlexander V. Chernikov } 1977b074b7bbSAlexander V. Chernikov 1978b074b7bbSAlexander V. Chernikov static struct table_config * 197968394ec8SAlexander V. Chernikov alloc_table_config(struct ip_fw_chain *ch, struct tid_info *ti, 1980914bffb6SAlexander V. Chernikov struct table_algo *ta, char *aname, uint8_t tflags, uint8_t vtype) 1981b074b7bbSAlexander V. Chernikov { 1982b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1983b074b7bbSAlexander V. Chernikov struct table_config *tc; 1984b074b7bbSAlexander V. Chernikov int error; 1985ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1986ac35ff17SAlexander V. Chernikov uint32_t set; 1987b074b7bbSAlexander V. Chernikov 1988b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1989ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1990ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1991b074b7bbSAlexander V. Chernikov return (NULL); 1992ac35ff17SAlexander V. Chernikov name = ntlv->name; 1993ac35ff17SAlexander V. Chernikov set = ntlv->set; 1994b074b7bbSAlexander V. Chernikov } else { 1995b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1996b074b7bbSAlexander V. Chernikov name = bname; 1997ac35ff17SAlexander V. Chernikov set = 0; 1998b074b7bbSAlexander V. Chernikov } 1999b074b7bbSAlexander V. Chernikov 2000b074b7bbSAlexander V. Chernikov tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO); 2001b074b7bbSAlexander V. Chernikov tc->no.name = tc->tablename; 2002b074b7bbSAlexander V. Chernikov tc->no.type = ti->type; 2003ac35ff17SAlexander V. Chernikov tc->no.set = set; 2004914bffb6SAlexander V. Chernikov tc->tflags = tflags; 20059f7d47b0SAlexander V. Chernikov tc->ta = ta; 2006b074b7bbSAlexander V. Chernikov strlcpy(tc->tablename, name, sizeof(tc->tablename)); 2007ac35ff17SAlexander V. Chernikov /* Set default value type to u32 for compability reasons */ 2008db785d31SAlexander V. Chernikov if (vtype == 0) 2009ac35ff17SAlexander V. Chernikov tc->vtype = IPFW_VTYPE_U32; 2010db785d31SAlexander V. Chernikov else 2011db785d31SAlexander V. Chernikov tc->vtype = vtype; 2012b074b7bbSAlexander V. Chernikov 2013b074b7bbSAlexander V. Chernikov if (ti->tlvs == NULL) { 2014b074b7bbSAlexander V. Chernikov tc->no.compat = 1; 2015b074b7bbSAlexander V. Chernikov tc->no.uidx = ti->uidx; 2016b074b7bbSAlexander V. Chernikov } 2017b074b7bbSAlexander V. Chernikov 2018b074b7bbSAlexander V. Chernikov /* Preallocate data structures for new tables */ 2019914bffb6SAlexander V. Chernikov error = ta->init(ch, &tc->astate, &tc->ti, aname, tflags); 2020b074b7bbSAlexander V. Chernikov if (error != 0) { 2021b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 2022b074b7bbSAlexander V. Chernikov return (NULL); 2023b074b7bbSAlexander V. Chernikov } 2024b074b7bbSAlexander V. Chernikov 2025b074b7bbSAlexander V. Chernikov return (tc); 2026b074b7bbSAlexander V. Chernikov } 2027b074b7bbSAlexander V. Chernikov 2028b074b7bbSAlexander V. Chernikov static void 2029b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc) 2030b074b7bbSAlexander V. Chernikov { 2031b074b7bbSAlexander V. Chernikov 2032b074b7bbSAlexander V. Chernikov if (tc->linked == 0) 203368394ec8SAlexander V. Chernikov tc->ta->destroy(tc->astate, &tc->ti); 2034b074b7bbSAlexander V. Chernikov 2035b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 2036b074b7bbSAlexander V. Chernikov } 2037b074b7bbSAlexander V. Chernikov 2038b074b7bbSAlexander V. Chernikov /* 2039b074b7bbSAlexander V. Chernikov * Links @tc to @chain table named instance. 2040b074b7bbSAlexander V. Chernikov * Sets appropriate type/states in @chain table info. 2041b074b7bbSAlexander V. Chernikov */ 2042b074b7bbSAlexander V. Chernikov static void 20439f7d47b0SAlexander V. Chernikov link_table(struct ip_fw_chain *ch, struct table_config *tc) 2044b074b7bbSAlexander V. Chernikov { 2045b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 20469f7d47b0SAlexander V. Chernikov struct table_info *ti; 2047b074b7bbSAlexander V. Chernikov uint16_t kidx; 2048b074b7bbSAlexander V. Chernikov 20499f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 20509f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 2051b074b7bbSAlexander V. Chernikov 20529f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 2053b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 2054b074b7bbSAlexander V. Chernikov 2055b074b7bbSAlexander V. Chernikov ipfw_objhash_add(ni, &tc->no); 20569f7d47b0SAlexander V. Chernikov 20579f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 20589f7d47b0SAlexander V. Chernikov *ti = tc->ti; 2059b074b7bbSAlexander V. Chernikov 206068394ec8SAlexander V. Chernikov /* Notify algo on real @ti address */ 206168394ec8SAlexander V. Chernikov if (tc->ta->change_ti != NULL) 206268394ec8SAlexander V. Chernikov tc->ta->change_ti(tc->astate, ti); 206368394ec8SAlexander V. Chernikov 2064b074b7bbSAlexander V. Chernikov tc->linked = 1; 20659d099b4fSAlexander V. Chernikov tc->ta->refcnt++; 2066b074b7bbSAlexander V. Chernikov } 2067b074b7bbSAlexander V. Chernikov 2068b074b7bbSAlexander V. Chernikov /* 2069b074b7bbSAlexander V. Chernikov * Unlinks @tc from @chain table named instance. 2070b074b7bbSAlexander V. Chernikov * Zeroes states in @chain and stores them in @tc. 2071b074b7bbSAlexander V. Chernikov */ 2072b074b7bbSAlexander V. Chernikov static void 20739f7d47b0SAlexander V. Chernikov unlink_table(struct ip_fw_chain *ch, struct table_config *tc) 2074b074b7bbSAlexander V. Chernikov { 2075b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 20769f7d47b0SAlexander V. Chernikov struct table_info *ti; 2077b074b7bbSAlexander V. Chernikov uint16_t kidx; 2078b074b7bbSAlexander V. Chernikov 20799f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 20809f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 2081b074b7bbSAlexander V. Chernikov 20829f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 2083b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 2084b074b7bbSAlexander V. Chernikov 20859f7d47b0SAlexander V. Chernikov /* Clear state. @ti copy is already saved inside @tc */ 2086b074b7bbSAlexander V. Chernikov ipfw_objhash_del(ni, &tc->no); 20879f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 20889f7d47b0SAlexander V. Chernikov memset(ti, 0, sizeof(struct table_info)); 2089b074b7bbSAlexander V. Chernikov tc->linked = 0; 20909d099b4fSAlexander V. Chernikov tc->ta->refcnt--; 209168394ec8SAlexander V. Chernikov 209268394ec8SAlexander V. Chernikov /* Notify algo on real @ti address */ 209368394ec8SAlexander V. Chernikov if (tc->ta->change_ti != NULL) 209468394ec8SAlexander V. Chernikov tc->ta->change_ti(tc->astate, NULL); 2095b074b7bbSAlexander V. Chernikov } 2096b074b7bbSAlexander V. Chernikov 2097b074b7bbSAlexander V. Chernikov /* 2098b074b7bbSAlexander V. Chernikov * Finds named object by @uidx number. 2099b074b7bbSAlexander V. Chernikov * Refs found object, allocate new index for non-existing object. 21009490a627SAlexander V. Chernikov * Fills in @oib with userland/kernel indexes. 21019490a627SAlexander V. Chernikov * First free oidx pointer is saved back in @oib. 2102b074b7bbSAlexander V. Chernikov * 2103b074b7bbSAlexander V. Chernikov * Returns 0 on success. 2104b074b7bbSAlexander V. Chernikov */ 2105b074b7bbSAlexander V. Chernikov static int 21069490a627SAlexander V. Chernikov bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule, 21079490a627SAlexander V. Chernikov struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti) 2108b074b7bbSAlexander V. Chernikov { 2109b074b7bbSAlexander V. Chernikov struct table_config *tc; 21109490a627SAlexander V. Chernikov struct namedobj_instance *ni; 21119490a627SAlexander V. Chernikov struct named_object *no; 21129490a627SAlexander V. Chernikov int error, l, cmdlen; 21139490a627SAlexander V. Chernikov ipfw_insn *cmd; 21149490a627SAlexander V. Chernikov struct obj_idx *pidx, *p; 21159490a627SAlexander V. Chernikov 21169490a627SAlexander V. Chernikov pidx = *oib; 21179490a627SAlexander V. Chernikov l = rule->cmd_len; 21189490a627SAlexander V. Chernikov cmd = rule->cmd; 21199490a627SAlexander V. Chernikov cmdlen = 0; 21209490a627SAlexander V. Chernikov error = 0; 21219490a627SAlexander V. Chernikov 21229490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 21239490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 21249490a627SAlexander V. Chernikov 21259490a627SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 21269490a627SAlexander V. Chernikov cmdlen = F_LEN(cmd); 21279490a627SAlexander V. Chernikov 21289490a627SAlexander V. Chernikov if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0) 21299490a627SAlexander V. Chernikov continue; 2130b074b7bbSAlexander V. Chernikov 2131b074b7bbSAlexander V. Chernikov pidx->uidx = ti->uidx; 2132b074b7bbSAlexander V. Chernikov pidx->type = ti->type; 2133b074b7bbSAlexander V. Chernikov 21349490a627SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 21359490a627SAlexander V. Chernikov if (tc->no.type != ti->type) { 21369490a627SAlexander V. Chernikov /* Incompatible types */ 21379490a627SAlexander V. Chernikov error = EINVAL; 21389490a627SAlexander V. Chernikov break; 21399490a627SAlexander V. Chernikov } 21409f7d47b0SAlexander V. Chernikov 21419490a627SAlexander V. Chernikov /* Reference found table and save kidx */ 21429490a627SAlexander V. Chernikov tc->no.refcnt++; 21439490a627SAlexander V. Chernikov pidx->kidx = tc->no.kidx; 21449490a627SAlexander V. Chernikov pidx++; 21459490a627SAlexander V. Chernikov continue; 21469490a627SAlexander V. Chernikov } 21479490a627SAlexander V. Chernikov 21489490a627SAlexander V. Chernikov /* Table not found. Allocate new index and save for later */ 2149ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &pidx->kidx) != 0) { 2150ac35ff17SAlexander V. Chernikov printf("Unable to allocate table %s index in set %u." 2151b074b7bbSAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 2152ac35ff17SAlexander V. Chernikov "", ti->set); 21539490a627SAlexander V. Chernikov error = EBUSY; 21549490a627SAlexander V. Chernikov break; 2155b074b7bbSAlexander V. Chernikov } 2156b074b7bbSAlexander V. Chernikov 2157b074b7bbSAlexander V. Chernikov ci->new_tables++; 21589490a627SAlexander V. Chernikov pidx->new = 1; 21599490a627SAlexander V. Chernikov pidx++; 2160b074b7bbSAlexander V. Chernikov } 2161b074b7bbSAlexander V. Chernikov 21629490a627SAlexander V. Chernikov if (error != 0) { 21639490a627SAlexander V. Chernikov /* Unref everything we have already done */ 21649490a627SAlexander V. Chernikov for (p = *oib; p < pidx; p++) { 21659490a627SAlexander V. Chernikov if (p->new != 0) { 2166ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, p->kidx); 21679490a627SAlexander V. Chernikov continue; 21689490a627SAlexander V. Chernikov } 2169b074b7bbSAlexander V. Chernikov 21709490a627SAlexander V. Chernikov /* Find & unref by existing idx */ 2171ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, p->kidx); 21729490a627SAlexander V. Chernikov KASSERT(no != NULL, ("Ref'd table %d disappeared", 21739490a627SAlexander V. Chernikov p->kidx)); 2174b074b7bbSAlexander V. Chernikov 21759490a627SAlexander V. Chernikov no->refcnt--; 21769490a627SAlexander V. Chernikov } 21779490a627SAlexander V. Chernikov } 21789490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2179b074b7bbSAlexander V. Chernikov 21809490a627SAlexander V. Chernikov *oib = pidx; 21819490a627SAlexander V. Chernikov 21829490a627SAlexander V. Chernikov return (error); 2183b074b7bbSAlexander V. Chernikov } 2184b074b7bbSAlexander V. Chernikov 2185b074b7bbSAlexander V. Chernikov /* 2186b074b7bbSAlexander V. Chernikov * Compatibility function for old ipfw(8) binaries. 2187b074b7bbSAlexander V. Chernikov * Rewrites table kernel indices with userland ones. 2188b074b7bbSAlexander V. Chernikov * Works for \d+ talbes only (e.g. for tables, converted 2189b074b7bbSAlexander V. Chernikov * from old numbered system calls). 2190b074b7bbSAlexander V. Chernikov * 2191b074b7bbSAlexander V. Chernikov * Returns 0 on success. 2192b074b7bbSAlexander V. Chernikov * Raises error on any other tables. 2193b074b7bbSAlexander V. Chernikov */ 2194b074b7bbSAlexander V. Chernikov int 21957e767c79SAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw_rule0 *rule) 2196b074b7bbSAlexander V. Chernikov { 21971832a7b3SAlexander V. Chernikov int cmdlen, error, l; 2198b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 21991832a7b3SAlexander V. Chernikov uint16_t kidx, uidx; 2200b074b7bbSAlexander V. Chernikov uint8_t type; 2201b074b7bbSAlexander V. Chernikov struct named_object *no; 2202b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2203b074b7bbSAlexander V. Chernikov 2204b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 22051832a7b3SAlexander V. Chernikov error = 0; 2206b074b7bbSAlexander V. Chernikov 2207b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 2208b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 2209b074b7bbSAlexander V. Chernikov cmdlen = 0; 2210b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2211b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2212b074b7bbSAlexander V. Chernikov 2213b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2214b074b7bbSAlexander V. Chernikov continue; 2215b074b7bbSAlexander V. Chernikov 2216ac35ff17SAlexander V. Chernikov if ((no = ipfw_objhash_lookup_kidx(ni, kidx)) == NULL) 2217b074b7bbSAlexander V. Chernikov return (1); 2218b074b7bbSAlexander V. Chernikov 22191832a7b3SAlexander V. Chernikov uidx = no->uidx; 22201832a7b3SAlexander V. Chernikov if (no->compat == 0) { 2221b074b7bbSAlexander V. Chernikov 22221832a7b3SAlexander V. Chernikov /* 22231832a7b3SAlexander V. Chernikov * We are called via legacy opcode. 22241832a7b3SAlexander V. Chernikov * Save error and show table as fake number 22251832a7b3SAlexander V. Chernikov * not to make ipfw(8) hang. 22261832a7b3SAlexander V. Chernikov */ 22271832a7b3SAlexander V. Chernikov uidx = 65535; 22281832a7b3SAlexander V. Chernikov error = 2; 2229b074b7bbSAlexander V. Chernikov } 2230b074b7bbSAlexander V. Chernikov 22311832a7b3SAlexander V. Chernikov update_table_opcode(cmd, uidx); 22321832a7b3SAlexander V. Chernikov } 22331832a7b3SAlexander V. Chernikov 22341832a7b3SAlexander V. Chernikov return (error); 2235b074b7bbSAlexander V. Chernikov } 2236b074b7bbSAlexander V. Chernikov 2237563b5ab1SAlexander V. Chernikov /* 2238563b5ab1SAlexander V. Chernikov * Sets every table kidx in @bmask which is used in rule @rule. 2239563b5ab1SAlexander V. Chernikov * 2240563b5ab1SAlexander V. Chernikov * Returns number of newly-referenced tables. 2241563b5ab1SAlexander V. Chernikov */ 2242563b5ab1SAlexander V. Chernikov int 2243563b5ab1SAlexander V. Chernikov ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule, 2244563b5ab1SAlexander V. Chernikov uint32_t *bmask) 2245563b5ab1SAlexander V. Chernikov { 2246563b5ab1SAlexander V. Chernikov int cmdlen, l, count; 2247563b5ab1SAlexander V. Chernikov ipfw_insn *cmd; 2248563b5ab1SAlexander V. Chernikov uint16_t kidx; 2249563b5ab1SAlexander V. Chernikov uint8_t type; 2250563b5ab1SAlexander V. Chernikov 2251563b5ab1SAlexander V. Chernikov l = rule->cmd_len; 2252563b5ab1SAlexander V. Chernikov cmd = rule->cmd; 2253563b5ab1SAlexander V. Chernikov cmdlen = 0; 2254563b5ab1SAlexander V. Chernikov count = 0; 2255563b5ab1SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2256563b5ab1SAlexander V. Chernikov cmdlen = F_LEN(cmd); 2257563b5ab1SAlexander V. Chernikov 2258563b5ab1SAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2259563b5ab1SAlexander V. Chernikov continue; 2260563b5ab1SAlexander V. Chernikov 2261563b5ab1SAlexander V. Chernikov if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0) 2262563b5ab1SAlexander V. Chernikov count++; 2263563b5ab1SAlexander V. Chernikov 2264563b5ab1SAlexander V. Chernikov bmask[kidx / 32] |= 1 << (kidx % 32); 2265563b5ab1SAlexander V. Chernikov } 2266563b5ab1SAlexander V. Chernikov 2267563b5ab1SAlexander V. Chernikov return (count); 2268563b5ab1SAlexander V. Chernikov } 2269563b5ab1SAlexander V. Chernikov 2270563b5ab1SAlexander V. Chernikov 2271b074b7bbSAlexander V. Chernikov 2272b074b7bbSAlexander V. Chernikov /* 2273b074b7bbSAlexander V. Chernikov * Checks is opcode is referencing table of appropriate type. 2274b074b7bbSAlexander V. Chernikov * Adds reference count for found table if true. 2275b074b7bbSAlexander V. Chernikov * Rewrites user-supplied opcode values with kernel ones. 2276b074b7bbSAlexander V. Chernikov * 2277b074b7bbSAlexander V. Chernikov * Returns 0 on success and appropriate error code otherwise. 2278b074b7bbSAlexander V. Chernikov */ 2279b074b7bbSAlexander V. Chernikov int 2280b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, 2281b074b7bbSAlexander V. Chernikov struct rule_check_info *ci) 2282b074b7bbSAlexander V. Chernikov { 2283b074b7bbSAlexander V. Chernikov int cmdlen, error, ftype, l; 2284b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 2285b074b7bbSAlexander V. Chernikov uint16_t uidx; 2286b074b7bbSAlexander V. Chernikov uint8_t type; 2287b074b7bbSAlexander V. Chernikov struct table_config *tc; 22889f7d47b0SAlexander V. Chernikov struct table_algo *ta; 2289b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2290b074b7bbSAlexander V. Chernikov struct named_object *no, *no_n, *no_tmp; 22919490a627SAlexander V. Chernikov struct obj_idx *p, *pidx_first, *pidx_last; 2292b074b7bbSAlexander V. Chernikov struct namedobjects_head nh; 2293b074b7bbSAlexander V. Chernikov struct tid_info ti; 2294b074b7bbSAlexander V. Chernikov 2295b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 2296b074b7bbSAlexander V. Chernikov 22979490a627SAlexander V. Chernikov /* Prepare queue to store configs */ 22989490a627SAlexander V. Chernikov TAILQ_INIT(&nh); 22999490a627SAlexander V. Chernikov 2300b074b7bbSAlexander V. Chernikov /* 2301b074b7bbSAlexander V. Chernikov * Prepare an array for storing opcode indices. 2302b074b7bbSAlexander V. Chernikov * Use stack allocation by default. 2303b074b7bbSAlexander V. Chernikov */ 2304b074b7bbSAlexander V. Chernikov if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 2305b074b7bbSAlexander V. Chernikov /* Stack */ 23069490a627SAlexander V. Chernikov pidx_first = ci->obuf; 2307b074b7bbSAlexander V. Chernikov } else 23089490a627SAlexander V. Chernikov pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx), 2309b074b7bbSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 2310b074b7bbSAlexander V. Chernikov 23119490a627SAlexander V. Chernikov pidx_last = pidx_first; 2312b074b7bbSAlexander V. Chernikov error = 0; 2313b074b7bbSAlexander V. Chernikov 2314b074b7bbSAlexander V. Chernikov type = 0; 2315b074b7bbSAlexander V. Chernikov ftype = 0; 2316b074b7bbSAlexander V. Chernikov 2317b074b7bbSAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 23181832a7b3SAlexander V. Chernikov 23191832a7b3SAlexander V. Chernikov /* 23201832a7b3SAlexander V. Chernikov * Use default set for looking up tables (old way) or 23211832a7b3SAlexander V. Chernikov * use set rule is assigned to (new way). 23221832a7b3SAlexander V. Chernikov */ 23231832a7b3SAlexander V. Chernikov ti.set = (V_fw_tables_sets != 0) ? ci->krule->set : 0; 23246c2997ffSAlexander V. Chernikov if (ci->ctlv != NULL) { 23256c2997ffSAlexander V. Chernikov ti.tlvs = (void *)(ci->ctlv + 1); 23266c2997ffSAlexander V. Chernikov ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv); 23276c2997ffSAlexander V. Chernikov } 2328b074b7bbSAlexander V. Chernikov 2329b074b7bbSAlexander V. Chernikov /* 23309490a627SAlexander V. Chernikov * Stage 1: reference existing tables, determine number 23319490a627SAlexander V. Chernikov * of tables we need to allocate and allocate indexes for each. 2332b074b7bbSAlexander V. Chernikov */ 23339490a627SAlexander V. Chernikov error = bind_table_rule(chain, ci->krule, ci, &pidx_last, &ti); 2334b074b7bbSAlexander V. Chernikov 2335b074b7bbSAlexander V. Chernikov if (error != 0) { 23369490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 23379490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 2338b074b7bbSAlexander V. Chernikov 2339b074b7bbSAlexander V. Chernikov return (error); 2340b074b7bbSAlexander V. Chernikov } 2341b074b7bbSAlexander V. Chernikov 2342b074b7bbSAlexander V. Chernikov /* 2343b074b7bbSAlexander V. Chernikov * Stage 2: allocate table configs for every non-existent table 2344b074b7bbSAlexander V. Chernikov */ 2345b074b7bbSAlexander V. Chernikov 23469f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 23479490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 2348b074b7bbSAlexander V. Chernikov if (p->new == 0) 2349b074b7bbSAlexander V. Chernikov continue; 2350b074b7bbSAlexander V. Chernikov 2351b074b7bbSAlexander V. Chernikov ti.uidx = p->uidx; 2352b074b7bbSAlexander V. Chernikov ti.type = p->type; 23539f7d47b0SAlexander V. Chernikov ti.atype = 0; 2354b074b7bbSAlexander V. Chernikov 23559490a627SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti, NULL); 23569f7d47b0SAlexander V. Chernikov if (ta == NULL) { 23579f7d47b0SAlexander V. Chernikov error = ENOTSUP; 23589f7d47b0SAlexander V. Chernikov goto free; 23599f7d47b0SAlexander V. Chernikov } 2360914bffb6SAlexander V. Chernikov tc = alloc_table_config(chain, &ti, ta, NULL, 0, 236168394ec8SAlexander V. Chernikov IPFW_VTYPE_U32); 2362b074b7bbSAlexander V. Chernikov 2363b074b7bbSAlexander V. Chernikov if (tc == NULL) { 2364b074b7bbSAlexander V. Chernikov error = ENOMEM; 2365b074b7bbSAlexander V. Chernikov goto free; 2366b074b7bbSAlexander V. Chernikov } 2367b074b7bbSAlexander V. Chernikov 2368b074b7bbSAlexander V. Chernikov tc->no.kidx = p->kidx; 2369b074b7bbSAlexander V. Chernikov tc->no.refcnt = 1; 2370b074b7bbSAlexander V. Chernikov 2371b074b7bbSAlexander V. Chernikov /* Add to list */ 2372b074b7bbSAlexander V. Chernikov TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next); 2373b074b7bbSAlexander V. Chernikov } 2374b074b7bbSAlexander V. Chernikov 2375b074b7bbSAlexander V. Chernikov /* 2376b074b7bbSAlexander V. Chernikov * Stage 2.1: Check if we're going to create 2 tables 2377b074b7bbSAlexander V. Chernikov * with the same name, but different table types. 2378b074b7bbSAlexander V. Chernikov */ 2379b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no, &nh, nn_next) { 2380b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no_tmp, &nh, nn_next) { 23819490a627SAlexander V. Chernikov if (ipfw_objhash_same_name(ni, no, no_tmp) == 0) 2382b074b7bbSAlexander V. Chernikov continue; 2383b074b7bbSAlexander V. Chernikov if (no->type != no_tmp->type) { 2384b074b7bbSAlexander V. Chernikov error = EINVAL; 2385b074b7bbSAlexander V. Chernikov goto free; 2386b074b7bbSAlexander V. Chernikov } 2387b074b7bbSAlexander V. Chernikov } 2388b074b7bbSAlexander V. Chernikov } 23899f7d47b0SAlexander V. Chernikov } 2390b074b7bbSAlexander V. Chernikov 23919f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 23929f7d47b0SAlexander V. Chernikov 23939f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 2394b074b7bbSAlexander V. Chernikov /* 2395b074b7bbSAlexander V. Chernikov * Stage 3: link & reference new table configs 2396b074b7bbSAlexander V. Chernikov */ 2397b074b7bbSAlexander V. Chernikov 2398b074b7bbSAlexander V. Chernikov 2399b074b7bbSAlexander V. Chernikov /* 2400b074b7bbSAlexander V. Chernikov * Step 3.1: Check if some tables we need to create have been 2401b074b7bbSAlexander V. Chernikov * already created with different table type. 2402b074b7bbSAlexander V. Chernikov */ 2403b074b7bbSAlexander V. Chernikov 2404b074b7bbSAlexander V. Chernikov error = 0; 2405b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2406b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 2407b074b7bbSAlexander V. Chernikov if (no_n == NULL) 2408b074b7bbSAlexander V. Chernikov continue; 2409b074b7bbSAlexander V. Chernikov 2410b074b7bbSAlexander V. Chernikov if (no_n->type != no->type) { 2411b074b7bbSAlexander V. Chernikov error = EINVAL; 2412b074b7bbSAlexander V. Chernikov break; 2413b074b7bbSAlexander V. Chernikov } 2414b074b7bbSAlexander V. Chernikov 2415b074b7bbSAlexander V. Chernikov } 2416b074b7bbSAlexander V. Chernikov 2417b074b7bbSAlexander V. Chernikov if (error != 0) { 2418b074b7bbSAlexander V. Chernikov /* 2419b074b7bbSAlexander V. Chernikov * Someone has allocated table with different table type. 2420b074b7bbSAlexander V. Chernikov * We have to rollback everything. 2421b074b7bbSAlexander V. Chernikov */ 2422b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 2423b074b7bbSAlexander V. Chernikov goto free; 2424b074b7bbSAlexander V. Chernikov } 2425b074b7bbSAlexander V. Chernikov 2426b074b7bbSAlexander V. Chernikov /* 24279f7d47b0SAlexander V. Chernikov * Attach new tables. 24289f7d47b0SAlexander V. Chernikov * We need to set table pointers for each new table, 2429b074b7bbSAlexander V. Chernikov * so we have to acquire main WLOCK. 2430b074b7bbSAlexander V. Chernikov */ 2431b074b7bbSAlexander V. Chernikov IPFW_WLOCK(chain); 2432b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2433b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 2434b074b7bbSAlexander V. Chernikov 24359490a627SAlexander V. Chernikov if (no_n == NULL) { 24369490a627SAlexander V. Chernikov /* New table. Attach to runtime hash */ 24379490a627SAlexander V. Chernikov TAILQ_REMOVE(&nh, no, nn_next); 24389490a627SAlexander V. Chernikov link_table(chain, (struct table_config *)no); 2439b074b7bbSAlexander V. Chernikov continue; 2440b074b7bbSAlexander V. Chernikov } 2441b074b7bbSAlexander V. Chernikov 24429490a627SAlexander V. Chernikov /* 24439490a627SAlexander V. Chernikov * Newly-allocated table with the same type. 24449490a627SAlexander V. Chernikov * Reference it and update out @pidx array 24459490a627SAlexander V. Chernikov * rewrite info. 24469490a627SAlexander V. Chernikov */ 24479490a627SAlexander V. Chernikov no_n->refcnt++; 24489490a627SAlexander V. Chernikov /* Keep oib array in sync: update kidx */ 24499490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 24509490a627SAlexander V. Chernikov if (p->kidx != no->kidx) 24519490a627SAlexander V. Chernikov continue; 24529490a627SAlexander V. Chernikov /* Update kidx */ 24539490a627SAlexander V. Chernikov p->kidx = no_n->kidx; 24549490a627SAlexander V. Chernikov break; 24559490a627SAlexander V. Chernikov } 2456b074b7bbSAlexander V. Chernikov } 2457b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(chain); 24589f7d47b0SAlexander V. Chernikov } 2459b074b7bbSAlexander V. Chernikov 2460b074b7bbSAlexander V. Chernikov /* Perform rule rewrite */ 2461b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 2462b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 2463b074b7bbSAlexander V. Chernikov cmdlen = 0; 24649490a627SAlexander V. Chernikov p = pidx_first; 2465b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2466b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2467b074b7bbSAlexander V. Chernikov 2468b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &uidx, &type) != 0) 2469b074b7bbSAlexander V. Chernikov continue; 24709490a627SAlexander V. Chernikov update_table_opcode(cmd, p->kidx); 24719490a627SAlexander V. Chernikov p++; 2472b074b7bbSAlexander V. Chernikov } 2473b074b7bbSAlexander V. Chernikov 2474b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 2475b074b7bbSAlexander V. Chernikov 2476b074b7bbSAlexander V. Chernikov error = 0; 2477b074b7bbSAlexander V. Chernikov 2478b074b7bbSAlexander V. Chernikov /* 2479b074b7bbSAlexander V. Chernikov * Stage 4: free resources 2480b074b7bbSAlexander V. Chernikov */ 2481b074b7bbSAlexander V. Chernikov free: 24829490a627SAlexander V. Chernikov if (!TAILQ_EMPTY(&nh)) { 24839490a627SAlexander V. Chernikov /* Free indexes first */ 24849490a627SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 24859490a627SAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2486ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, no->kidx); 24879490a627SAlexander V. Chernikov } 24889490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 24899490a627SAlexander V. Chernikov /* Free configs */ 2490b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) 2491b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 24929490a627SAlexander V. Chernikov } 2493b074b7bbSAlexander V. Chernikov 24949490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 24959490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 2496b074b7bbSAlexander V. Chernikov 2497b074b7bbSAlexander V. Chernikov return (error); 2498b074b7bbSAlexander V. Chernikov } 2499b074b7bbSAlexander V. Chernikov 2500b074b7bbSAlexander V. Chernikov /* 2501b074b7bbSAlexander V. Chernikov * Remove references from every table used in @rule. 2502b074b7bbSAlexander V. Chernikov */ 2503b074b7bbSAlexander V. Chernikov void 2504b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule) 2505b074b7bbSAlexander V. Chernikov { 2506b074b7bbSAlexander V. Chernikov int cmdlen, l; 2507b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 2508b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2509b074b7bbSAlexander V. Chernikov struct named_object *no; 2510b074b7bbSAlexander V. Chernikov uint16_t kidx; 2511b074b7bbSAlexander V. Chernikov uint8_t type; 2512b074b7bbSAlexander V. Chernikov 2513b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 2514b074b7bbSAlexander V. Chernikov 2515b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 2516b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 2517b074b7bbSAlexander V. Chernikov cmdlen = 0; 2518b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2519b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2520b074b7bbSAlexander V. Chernikov 2521b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2522b074b7bbSAlexander V. Chernikov continue; 2523b074b7bbSAlexander V. Chernikov 2524ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 2525b074b7bbSAlexander V. Chernikov 2526b074b7bbSAlexander V. Chernikov KASSERT(no != NULL, ("table id %d not found", kidx)); 2527b074b7bbSAlexander V. Chernikov KASSERT(no->type == type, ("wrong type %d (%d) for table id %d", 2528b074b7bbSAlexander V. Chernikov no->type, type, kidx)); 2529b074b7bbSAlexander V. Chernikov KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 2530b074b7bbSAlexander V. Chernikov kidx, no->refcnt)); 2531b074b7bbSAlexander V. Chernikov 2532b074b7bbSAlexander V. Chernikov no->refcnt--; 2533b074b7bbSAlexander V. Chernikov } 2534b074b7bbSAlexander V. Chernikov } 2535b074b7bbSAlexander V. Chernikov 2536b074b7bbSAlexander V. Chernikov 2537b074b7bbSAlexander V. Chernikov /* 2538b074b7bbSAlexander V. Chernikov * Removes table bindings for every rule in rule chain @head. 2539b074b7bbSAlexander V. Chernikov */ 2540b074b7bbSAlexander V. Chernikov void 2541b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head) 2542b074b7bbSAlexander V. Chernikov { 2543b074b7bbSAlexander V. Chernikov struct ip_fw *rule; 2544b074b7bbSAlexander V. Chernikov 2545b074b7bbSAlexander V. Chernikov while ((rule = head) != NULL) { 2546b074b7bbSAlexander V. Chernikov head = head->x_next; 2547b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(chain, rule); 2548b074b7bbSAlexander V. Chernikov } 2549b074b7bbSAlexander V. Chernikov } 2550b074b7bbSAlexander V. Chernikov 2551b074b7bbSAlexander V. Chernikov 25523b3a8eb9SGleb Smirnoff /* end of file */ 2553