13b3a8eb9SGleb Smirnoff /*- 23b3a8eb9SGleb Smirnoff * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. 33b3a8eb9SGleb Smirnoff * 43b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 53b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions 63b3a8eb9SGleb Smirnoff * are met: 73b3a8eb9SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 83b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 93b3a8eb9SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 103b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 113b3a8eb9SGleb Smirnoff * documentation and/or other materials provided with the distribution. 123b3a8eb9SGleb Smirnoff * 133b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 143b3a8eb9SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 153b3a8eb9SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 163b3a8eb9SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 173b3a8eb9SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 183b3a8eb9SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 193b3a8eb9SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 203b3a8eb9SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 213b3a8eb9SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 223b3a8eb9SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 233b3a8eb9SGleb Smirnoff * SUCH DAMAGE. 243b3a8eb9SGleb Smirnoff */ 253b3a8eb9SGleb Smirnoff 263b3a8eb9SGleb Smirnoff #include <sys/cdefs.h> 273b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$"); 283b3a8eb9SGleb Smirnoff 293b3a8eb9SGleb Smirnoff /* 30563b5ab1SAlexander V. Chernikov * Lookup table support for ipfw. 313b3a8eb9SGleb Smirnoff * 32ac35ff17SAlexander V. Chernikov * This file contains handlers for all generic tables' operations: 33563b5ab1SAlexander V. Chernikov * add/del/flush entries, list/dump tables etc.. 343b3a8eb9SGleb Smirnoff * 35563b5ab1SAlexander V. Chernikov * Table data modification is protected by both UH and runtimg lock 36563b5ab1SAlexander V. Chernikov * while reading configuration/data is protected by UH lock. 37563b5ab1SAlexander V. Chernikov * 38563b5ab1SAlexander V. Chernikov * Lookup algorithms for all table types are located in ip_fw_table_algo.c 393b3a8eb9SGleb Smirnoff */ 403b3a8eb9SGleb Smirnoff 413b3a8eb9SGleb Smirnoff #include "opt_ipfw.h" 423b3a8eb9SGleb Smirnoff 433b3a8eb9SGleb Smirnoff #include <sys/param.h> 443b3a8eb9SGleb Smirnoff #include <sys/systm.h> 453b3a8eb9SGleb Smirnoff #include <sys/malloc.h> 463b3a8eb9SGleb Smirnoff #include <sys/kernel.h> 473b3a8eb9SGleb Smirnoff #include <sys/lock.h> 483b3a8eb9SGleb Smirnoff #include <sys/rwlock.h> 493b3a8eb9SGleb Smirnoff #include <sys/socket.h> 50f1220db8SAlexander V. Chernikov #include <sys/socketvar.h> 513b3a8eb9SGleb Smirnoff #include <sys/queue.h> 523b3a8eb9SGleb Smirnoff #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 533b3a8eb9SGleb Smirnoff #include <net/route.h> 543b3a8eb9SGleb Smirnoff #include <net/vnet.h> 553b3a8eb9SGleb Smirnoff 563b3a8eb9SGleb Smirnoff #include <netinet/in.h> 573b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 583b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h> 593b3a8eb9SGleb Smirnoff 603b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h> 61ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 623b3a8eb9SGleb Smirnoff 633b3a8eb9SGleb Smirnoff 643b3a8eb9SGleb Smirnoff /* 65b074b7bbSAlexander V. Chernikov * Table has the following `type` concepts: 66b074b7bbSAlexander V. Chernikov * 679f7d47b0SAlexander V. Chernikov * `no.type` represents lookup key type (cidr, ifp, uid, etc..) 689f7d47b0SAlexander V. Chernikov * `ta->atype` represents exact lookup algorithm. 69b074b7bbSAlexander V. Chernikov * For example, we can use more efficient search schemes if we plan 70b074b7bbSAlexander V. Chernikov * to use some specific table for storing host-routes only. 719490a627SAlexander V. Chernikov * `ftype` (at the moment )is pure userland field helping to properly 729490a627SAlexander V. Chernikov * format value data e.g. "value is IPv4 nexthop" or "value is DSCP" 739490a627SAlexander V. Chernikov * or "value is port". 74b074b7bbSAlexander V. Chernikov * 75b074b7bbSAlexander V. Chernikov */ 76b074b7bbSAlexander V. Chernikov struct table_config { 77b074b7bbSAlexander V. Chernikov struct named_object no; 78ac35ff17SAlexander V. Chernikov uint8_t vtype; /* format table type */ 79b074b7bbSAlexander V. Chernikov uint8_t linked; /* 1 if already linked */ 80914bffb6SAlexander V. Chernikov uint8_t tflags; /* type flags */ 81914bffb6SAlexander V. Chernikov uint8_t spare; 82b074b7bbSAlexander V. Chernikov uint32_t count; /* Number of records */ 834c0c07a5SAlexander V. Chernikov uint32_t limit; /* Max number of records */ 84db785d31SAlexander V. Chernikov uint64_t flags; /* state flags */ 85b074b7bbSAlexander V. Chernikov char tablename[64]; /* table name */ 869f7d47b0SAlexander V. Chernikov struct table_algo *ta; /* Callbacks for given algo */ 879f7d47b0SAlexander V. Chernikov void *astate; /* algorithm state */ 889f7d47b0SAlexander V. Chernikov struct table_info ti; /* data to put to table_info */ 89b074b7bbSAlexander V. Chernikov }; 90b074b7bbSAlexander V. Chernikov 91b074b7bbSAlexander V. Chernikov struct tables_config { 92b074b7bbSAlexander V. Chernikov struct namedobj_instance *namehash; 939f7d47b0SAlexander V. Chernikov int algo_count; 949f7d47b0SAlexander V. Chernikov struct table_algo *algo[256]; 9557a1cf95SAlexander V. Chernikov struct table_algo *def_algo[IPFW_TABLE_MAXTYPE + 1]; 96b074b7bbSAlexander V. Chernikov }; 97b074b7bbSAlexander V. Chernikov 98b074b7bbSAlexander V. Chernikov static struct table_config *find_table(struct namedobj_instance *ni, 99b074b7bbSAlexander V. Chernikov struct tid_info *ti); 10068394ec8SAlexander V. Chernikov static struct table_config *alloc_table_config(struct ip_fw_chain *ch, 101914bffb6SAlexander V. Chernikov struct tid_info *ti, struct table_algo *ta, char *adata, uint8_t tflags, 102914bffb6SAlexander V. Chernikov uint8_t vtype); 103b074b7bbSAlexander V. Chernikov static void free_table_config(struct namedobj_instance *ni, 104b074b7bbSAlexander V. Chernikov struct table_config *tc); 105db785d31SAlexander V. Chernikov static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, 1064c0c07a5SAlexander V. Chernikov char *aname, ipfw_xtable_info *i); 107b074b7bbSAlexander V. Chernikov static void link_table(struct ip_fw_chain *chain, struct table_config *tc); 108b074b7bbSAlexander V. Chernikov static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc); 109b074b7bbSAlexander V. Chernikov static void free_table_state(void **state, void **xstate, uint8_t type); 1102d99a349SAlexander V. Chernikov static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 1112d99a349SAlexander V. Chernikov struct sockopt_data *sd); 112ac35ff17SAlexander V. Chernikov static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 113ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i); 11481d3153dSAlexander V. Chernikov static int dump_table_tentry(void *e, void *arg); 115f1220db8SAlexander V. Chernikov static int dump_table_xentry(void *e, void *arg); 116b074b7bbSAlexander V. Chernikov 1172d99a349SAlexander V. Chernikov static int ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd); 1182d99a349SAlexander V. Chernikov static int ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd); 119db785d31SAlexander V. Chernikov static int ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 120ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 121db785d31SAlexander V. Chernikov static int ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 122ac35ff17SAlexander V. Chernikov struct sockopt_data *sd); 123ac35ff17SAlexander V. Chernikov 124db785d31SAlexander V. Chernikov static int modify_table(struct ip_fw_chain *ch, struct table_config *tc, 125db785d31SAlexander V. Chernikov struct table_algo *ta, void *ta_buf, uint64_t pflags); 126ac35ff17SAlexander V. Chernikov static int destroy_table(struct ip_fw_chain *ch, struct tid_info *ti); 127d3a4f924SAlexander V. Chernikov 1289f7d47b0SAlexander V. Chernikov static struct table_algo *find_table_algo(struct tables_config *tableconf, 1299490a627SAlexander V. Chernikov struct tid_info *ti, char *name); 130b074b7bbSAlexander V. Chernikov 131b074b7bbSAlexander V. Chernikov #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) 132b074b7bbSAlexander V. Chernikov #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) 1339f7d47b0SAlexander V. Chernikov #define KIDX_TO_TI(ch, k) (&(((struct table_info *)(ch)->tablestate)[k])) 134b074b7bbSAlexander V. Chernikov 135b074b7bbSAlexander V. Chernikov 1363b3a8eb9SGleb Smirnoff int 1371832a7b3SAlexander V. Chernikov add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 138b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 1393b3a8eb9SGleb Smirnoff { 140db785d31SAlexander V. Chernikov struct table_config *tc; 1419f7d47b0SAlexander V. Chernikov struct table_algo *ta; 142b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 143b074b7bbSAlexander V. Chernikov uint16_t kidx; 1449f7d47b0SAlexander V. Chernikov int error; 145adea6201SAlexander V. Chernikov uint32_t num; 146db785d31SAlexander V. Chernikov uint64_t aflags; 1474c0c07a5SAlexander V. Chernikov ipfw_xtable_info xi; 1489f7d47b0SAlexander V. Chernikov char ta_buf[128]; 1493b3a8eb9SGleb Smirnoff 1509f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1519f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1529f7d47b0SAlexander V. Chernikov 1539f7d47b0SAlexander V. Chernikov /* 1549f7d47b0SAlexander V. Chernikov * Find and reference existing table. 1559f7d47b0SAlexander V. Chernikov */ 1569f7d47b0SAlexander V. Chernikov ta = NULL; 1579f7d47b0SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 1589f7d47b0SAlexander V. Chernikov /* check table type */ 1599f7d47b0SAlexander V. Chernikov if (tc->no.type != ti->type) { 1609f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1613b3a8eb9SGleb Smirnoff return (EINVAL); 1623b3a8eb9SGleb Smirnoff } 1633b3a8eb9SGleb Smirnoff 1644c0c07a5SAlexander V. Chernikov /* Try to exit early on limit hit */ 1654c0c07a5SAlexander V. Chernikov if (tc->limit != 0 && tc->count == tc->limit && 1664c0c07a5SAlexander V. Chernikov (tei->flags & TEI_FLAGS_UPDATE) == 0) { 1674c0c07a5SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1684c0c07a5SAlexander V. Chernikov return (EFBIG); 1694c0c07a5SAlexander V. Chernikov } 1704c0c07a5SAlexander V. Chernikov 1719f7d47b0SAlexander V. Chernikov /* Reference and unlock */ 1729f7d47b0SAlexander V. Chernikov tc->no.refcnt++; 1739f7d47b0SAlexander V. Chernikov ta = tc->ta; 174db785d31SAlexander V. Chernikov aflags = tc->flags; 1759f7d47b0SAlexander V. Chernikov } 1769f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1773b3a8eb9SGleb Smirnoff 178ac35ff17SAlexander V. Chernikov if (tc == NULL) { 179db785d31SAlexander V. Chernikov /* Compability mode: create new table for old clients */ 180db785d31SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_COMPAT) == 0) 181db785d31SAlexander V. Chernikov return (ESRCH); 1823b3a8eb9SGleb Smirnoff 1834c0c07a5SAlexander V. Chernikov memset(&xi, 0, sizeof(xi)); 1844c0c07a5SAlexander V. Chernikov xi.vtype = IPFW_VTYPE_U32; 1854c0c07a5SAlexander V. Chernikov 1864c0c07a5SAlexander V. Chernikov error = create_table_internal(ch, ti, NULL, &xi); 187db785d31SAlexander V. Chernikov 188db785d31SAlexander V. Chernikov if (error != 0) 189db785d31SAlexander V. Chernikov return (error); 190db785d31SAlexander V. Chernikov 191db785d31SAlexander V. Chernikov /* Let's try to find & reference another time */ 192db785d31SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 193db785d31SAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 194db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 195db785d31SAlexander V. Chernikov return (EINVAL); 196db785d31SAlexander V. Chernikov } 197db785d31SAlexander V. Chernikov 198db785d31SAlexander V. Chernikov if (tc->no.type != ti->type) { 199db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 200db785d31SAlexander V. Chernikov return (EINVAL); 201db785d31SAlexander V. Chernikov } 202db785d31SAlexander V. Chernikov 203db785d31SAlexander V. Chernikov /* Reference and unlock */ 204db785d31SAlexander V. Chernikov tc->no.refcnt++; 205db785d31SAlexander V. Chernikov ta = tc->ta; 206db785d31SAlexander V. Chernikov aflags = tc->flags; 207db785d31SAlexander V. Chernikov 208db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 209db785d31SAlexander V. Chernikov } 210db785d31SAlexander V. Chernikov 211db785d31SAlexander V. Chernikov if (aflags != 0) { 212db785d31SAlexander V. Chernikov 213db785d31SAlexander V. Chernikov /* 214db785d31SAlexander V. Chernikov * Previous add/delete call returned non-zero state. 215db785d31SAlexander V. Chernikov * Run appropriate handler. 216db785d31SAlexander V. Chernikov */ 217db785d31SAlexander V. Chernikov error = modify_table(ch, tc, ta, &ta_buf, aflags); 218db785d31SAlexander V. Chernikov if (error != 0) 219db785d31SAlexander V. Chernikov return (error); 2209f7d47b0SAlexander V. Chernikov } 2213b3a8eb9SGleb Smirnoff 2229f7d47b0SAlexander V. Chernikov /* Prepare record (allocate memory) */ 2239f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 22468394ec8SAlexander V. Chernikov error = ta->prepare_add(ch, tei, &ta_buf); 225db785d31SAlexander V. Chernikov if (error != 0) 2269f7d47b0SAlexander V. Chernikov return (error); 2273b3a8eb9SGleb Smirnoff 228b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 2293b3a8eb9SGleb Smirnoff 230b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 2313b3a8eb9SGleb Smirnoff 2329f7d47b0SAlexander V. Chernikov /* Drop reference we've used in first search */ 2339f7d47b0SAlexander V. Chernikov tc->no.refcnt--; 234db785d31SAlexander V. Chernikov /* Update aflags since it can be changed after previous read */ 235db785d31SAlexander V. Chernikov aflags = tc->flags; 236b074b7bbSAlexander V. Chernikov 2374c0c07a5SAlexander V. Chernikov /* Check limit before adding */ 2384c0c07a5SAlexander V. Chernikov if (tc->limit != 0 && tc->count == tc->limit) { 2394c0c07a5SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) { 2404c0c07a5SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2414c0c07a5SAlexander V. Chernikov return (EFBIG); 2424c0c07a5SAlexander V. Chernikov } 2434c0c07a5SAlexander V. Chernikov 2444c0c07a5SAlexander V. Chernikov /* 2454c0c07a5SAlexander V. Chernikov * We have UPDATE flag set. 2464c0c07a5SAlexander V. Chernikov * Permit updating record (if found), 2474c0c07a5SAlexander V. Chernikov * but restrict adding new one since we've 2484c0c07a5SAlexander V. Chernikov * already hit the limit. 2494c0c07a5SAlexander V. Chernikov */ 2504c0c07a5SAlexander V. Chernikov tei->flags |= TEI_FLAGS_DONTADD; 2514c0c07a5SAlexander V. Chernikov } 2524c0c07a5SAlexander V. Chernikov 253b074b7bbSAlexander V. Chernikov /* We've got valid table in @tc. Let's add data */ 2549f7d47b0SAlexander V. Chernikov kidx = tc->no.kidx; 2559f7d47b0SAlexander V. Chernikov ta = tc->ta; 256adea6201SAlexander V. Chernikov num = 0; 2579f7d47b0SAlexander V. Chernikov 258b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 259adea6201SAlexander V. Chernikov error = ta->add(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, 260adea6201SAlexander V. Chernikov &aflags, &num); 2613b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 2629f7d47b0SAlexander V. Chernikov 263ac35ff17SAlexander V. Chernikov /* Update number of records. */ 264adea6201SAlexander V. Chernikov if (error == 0) 265adea6201SAlexander V. Chernikov tc->count += num; 2669f7d47b0SAlexander V. Chernikov 267db785d31SAlexander V. Chernikov tc->flags = aflags; 268db785d31SAlexander V. Chernikov 269b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 270b074b7bbSAlexander V. Chernikov 271ac35ff17SAlexander V. Chernikov /* Run cleaning callback anyway */ 27268394ec8SAlexander V. Chernikov ta->flush_entry(ch, tei, &ta_buf); 273b074b7bbSAlexander V. Chernikov 2749f7d47b0SAlexander V. Chernikov return (error); 2753b3a8eb9SGleb Smirnoff } 2763b3a8eb9SGleb Smirnoff 2773b3a8eb9SGleb Smirnoff int 2781832a7b3SAlexander V. Chernikov del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 279b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 2803b3a8eb9SGleb Smirnoff { 281b074b7bbSAlexander V. Chernikov struct table_config *tc; 2829f7d47b0SAlexander V. Chernikov struct table_algo *ta; 283b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 284b074b7bbSAlexander V. Chernikov uint16_t kidx; 2859f7d47b0SAlexander V. Chernikov int error; 286adea6201SAlexander V. Chernikov uint32_t num; 287db785d31SAlexander V. Chernikov uint64_t aflags; 2889f7d47b0SAlexander V. Chernikov char ta_buf[128]; 2893b3a8eb9SGleb Smirnoff 2909f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 291b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 292b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 2939f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2943b3a8eb9SGleb Smirnoff return (ESRCH); 2953b3a8eb9SGleb Smirnoff } 2963b3a8eb9SGleb Smirnoff 297b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 2989f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2993b3a8eb9SGleb Smirnoff return (EINVAL); 3003b3a8eb9SGleb Smirnoff } 3019f7d47b0SAlexander V. Chernikov 302db785d31SAlexander V. Chernikov aflags = tc->flags; 3039f7d47b0SAlexander V. Chernikov ta = tc->ta; 3049f7d47b0SAlexander V. Chernikov 305db785d31SAlexander V. Chernikov if (aflags != 0) { 306db785d31SAlexander V. Chernikov 307db785d31SAlexander V. Chernikov /* 308db785d31SAlexander V. Chernikov * Give the chance to algo to shrink its state. 309db785d31SAlexander V. Chernikov */ 310db785d31SAlexander V. Chernikov tc->no.refcnt++; 311db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 312db785d31SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 313db785d31SAlexander V. Chernikov 314db785d31SAlexander V. Chernikov error = modify_table(ch, tc, ta, &ta_buf, aflags); 315db785d31SAlexander V. Chernikov 316db785d31SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 317db785d31SAlexander V. Chernikov tc->no.refcnt--; 318db785d31SAlexander V. Chernikov aflags = tc->flags; 319db785d31SAlexander V. Chernikov 320db785d31SAlexander V. Chernikov if (error != 0) { 321db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 322db785d31SAlexander V. Chernikov return (error); 323db785d31SAlexander V. Chernikov } 324db785d31SAlexander V. Chernikov } 325db785d31SAlexander V. Chernikov 326db785d31SAlexander V. Chernikov /* 327db785d31SAlexander V. Chernikov * We assume ta_buf size is enough for storing 328db785d31SAlexander V. Chernikov * prepare_del() key, so we're running under UH_LOCK here. 329db785d31SAlexander V. Chernikov */ 3309f7d47b0SAlexander V. Chernikov memset(&ta_buf, 0, sizeof(ta_buf)); 33168394ec8SAlexander V. Chernikov if ((error = ta->prepare_del(ch, tei, &ta_buf)) != 0) { 3329f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3339f7d47b0SAlexander V. Chernikov return (error); 3349f7d47b0SAlexander V. Chernikov } 3359f7d47b0SAlexander V. Chernikov 336b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 337adea6201SAlexander V. Chernikov num = 0; 338b074b7bbSAlexander V. Chernikov 339b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 340adea6201SAlexander V. Chernikov error = ta->del(tc->astate, KIDX_TO_TI(ch, kidx), tei, &ta_buf, 341adea6201SAlexander V. Chernikov &aflags, &num); 3423b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 3433b3a8eb9SGleb Smirnoff 3449f7d47b0SAlexander V. Chernikov if (error == 0) 345adea6201SAlexander V. Chernikov tc->count -= num; 346db785d31SAlexander V. Chernikov tc->flags = aflags; 347b074b7bbSAlexander V. Chernikov 3489f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 3493b3a8eb9SGleb Smirnoff 35068394ec8SAlexander V. Chernikov ta->flush_entry(ch, tei, &ta_buf); 351ac35ff17SAlexander V. Chernikov 352ac35ff17SAlexander V. Chernikov return (error); 353ac35ff17SAlexander V. Chernikov } 354ac35ff17SAlexander V. Chernikov 355db785d31SAlexander V. Chernikov /* 356db785d31SAlexander V. Chernikov * Runs callbacks to modify algo state (typically, table resize). 357db785d31SAlexander V. Chernikov * 358db785d31SAlexander V. Chernikov * Callbacks order: 359db785d31SAlexander V. Chernikov * 1) alloc_modify (no locks, M_WAITOK) - alloc new state based on @pflags. 360db785d31SAlexander V. Chernikov * 2) prepare_modifyt (UH_WLOCK) - copy old data into new storage 361db785d31SAlexander V. Chernikov * 3) modify (UH_WLOCK + WLOCK) - switch pointers 362db785d31SAlexander V. Chernikov * 4) flush_modify (no locks) - free state, if needed 363db785d31SAlexander V. Chernikov */ 364db785d31SAlexander V. Chernikov static int 365db785d31SAlexander V. Chernikov modify_table(struct ip_fw_chain *ch, struct table_config *tc, 366db785d31SAlexander V. Chernikov struct table_algo *ta, void *ta_buf, uint64_t pflags) 367db785d31SAlexander V. Chernikov { 368db785d31SAlexander V. Chernikov struct table_info *ti; 369db785d31SAlexander V. Chernikov int error; 370db785d31SAlexander V. Chernikov 371db785d31SAlexander V. Chernikov error = ta->prepare_mod(ta_buf, &pflags); 372db785d31SAlexander V. Chernikov if (error != 0) 373db785d31SAlexander V. Chernikov return (error); 374db785d31SAlexander V. Chernikov 375db785d31SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 376db785d31SAlexander V. Chernikov ti = KIDX_TO_TI(ch, tc->no.kidx); 377db785d31SAlexander V. Chernikov 37868394ec8SAlexander V. Chernikov error = ta->fill_mod(tc->astate, ti, ta_buf, &pflags); 379db785d31SAlexander V. Chernikov 380db785d31SAlexander V. Chernikov /* 381db785d31SAlexander V. Chernikov * prepare_mofify may return zero in @pflags to 382db785d31SAlexander V. Chernikov * indicate that modifications are not unnesessary. 383db785d31SAlexander V. Chernikov */ 384db785d31SAlexander V. Chernikov 385db785d31SAlexander V. Chernikov if (error == 0 && pflags != 0) { 386db785d31SAlexander V. Chernikov /* Do actual modification */ 387db785d31SAlexander V. Chernikov IPFW_WLOCK(ch); 38868394ec8SAlexander V. Chernikov ta->modify(tc->astate, ti, ta_buf, pflags); 389db785d31SAlexander V. Chernikov IPFW_WUNLOCK(ch); 390db785d31SAlexander V. Chernikov } 391db785d31SAlexander V. Chernikov 392db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 393db785d31SAlexander V. Chernikov 394db785d31SAlexander V. Chernikov ta->flush_mod(ta_buf); 395db785d31SAlexander V. Chernikov 396db785d31SAlexander V. Chernikov return (error); 397db785d31SAlexander V. Chernikov } 398db785d31SAlexander V. Chernikov 399ac35ff17SAlexander V. Chernikov int 400db785d31SAlexander V. Chernikov ipfw_manage_table_ent(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 401ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 402ac35ff17SAlexander V. Chernikov { 403ac35ff17SAlexander V. Chernikov int error; 404ac35ff17SAlexander V. Chernikov 405ac35ff17SAlexander V. Chernikov switch (op3->version) { 406ac35ff17SAlexander V. Chernikov case 0: 407db785d31SAlexander V. Chernikov error = ipfw_manage_table_ent_v0(ch, op3, sd); 408ac35ff17SAlexander V. Chernikov break; 409ac35ff17SAlexander V. Chernikov case 1: 410db785d31SAlexander V. Chernikov error = ipfw_manage_table_ent_v1(ch, op3, sd); 411ac35ff17SAlexander V. Chernikov break; 412ac35ff17SAlexander V. Chernikov default: 413ac35ff17SAlexander V. Chernikov error = ENOTSUP; 414ac35ff17SAlexander V. Chernikov } 415ac35ff17SAlexander V. Chernikov 416ac35ff17SAlexander V. Chernikov return (error); 417ac35ff17SAlexander V. Chernikov } 418ac35ff17SAlexander V. Chernikov 419ac35ff17SAlexander V. Chernikov /* 420ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 421ac35ff17SAlexander V. Chernikov * Data layout (v0): 422ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ipfw_table_xentry ] 423ac35ff17SAlexander V. Chernikov * 424ac35ff17SAlexander V. Chernikov * Returns 0 on success 425ac35ff17SAlexander V. Chernikov */ 426ac35ff17SAlexander V. Chernikov static int 427db785d31SAlexander V. Chernikov ipfw_manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 428ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 429ac35ff17SAlexander V. Chernikov { 430ac35ff17SAlexander V. Chernikov ipfw_table_xentry *xent; 431ac35ff17SAlexander V. Chernikov struct tentry_info tei; 432ac35ff17SAlexander V. Chernikov struct tid_info ti; 433ac35ff17SAlexander V. Chernikov int error, hdrlen, read; 434ac35ff17SAlexander V. Chernikov 435ac35ff17SAlexander V. Chernikov hdrlen = offsetof(ipfw_table_xentry, k); 436ac35ff17SAlexander V. Chernikov 437ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 438ac35ff17SAlexander V. Chernikov if (sd->valsize < (sizeof(*op3) + hdrlen)) 439ac35ff17SAlexander V. Chernikov return (EINVAL); 440ac35ff17SAlexander V. Chernikov 441ac35ff17SAlexander V. Chernikov read = sizeof(ip_fw3_opheader); 442ac35ff17SAlexander V. Chernikov 443ac35ff17SAlexander V. Chernikov /* Check if xentry len field is valid */ 444ac35ff17SAlexander V. Chernikov xent = (ipfw_table_xentry *)(op3 + 1); 445ac35ff17SAlexander V. Chernikov if (xent->len < hdrlen || xent->len + read > sd->valsize) 446ac35ff17SAlexander V. Chernikov return (EINVAL); 447ac35ff17SAlexander V. Chernikov 448ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 449ac35ff17SAlexander V. Chernikov tei.paddr = &xent->k; 450ac35ff17SAlexander V. Chernikov tei.masklen = xent->masklen; 451ac35ff17SAlexander V. Chernikov tei.value = xent->value; 452ac35ff17SAlexander V. Chernikov /* Old requests compability */ 453db785d31SAlexander V. Chernikov tei.flags = TEI_FLAGS_COMPAT; 454ac35ff17SAlexander V. Chernikov if (xent->type == IPFW_TABLE_CIDR) { 455ac35ff17SAlexander V. Chernikov if (xent->len - hdrlen == sizeof(in_addr_t)) 456ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET; 457ac35ff17SAlexander V. Chernikov else 458ac35ff17SAlexander V. Chernikov tei.subtype = AF_INET6; 459ac35ff17SAlexander V. Chernikov } 460ac35ff17SAlexander V. Chernikov 461ac35ff17SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 462ac35ff17SAlexander V. Chernikov ti.uidx = xent->tbl; 463ac35ff17SAlexander V. Chernikov ti.type = xent->type; 464ac35ff17SAlexander V. Chernikov 465ac35ff17SAlexander V. Chernikov error = (op3->opcode == IP_FW_TABLE_XADD) ? 4661832a7b3SAlexander V. Chernikov add_table_entry(ch, &ti, &tei) : 4671832a7b3SAlexander V. Chernikov del_table_entry(ch, &ti, &tei); 468ac35ff17SAlexander V. Chernikov 469ac35ff17SAlexander V. Chernikov return (error); 470ac35ff17SAlexander V. Chernikov } 471ac35ff17SAlexander V. Chernikov 472ac35ff17SAlexander V. Chernikov /* 473ac35ff17SAlexander V. Chernikov * Adds or deletes record in table. 474ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 475db785d31SAlexander V. Chernikov * Request: [ ipfw_obj_header 476db785d31SAlexander V. Chernikov * ipfw_obj_ctlv(IPFW_TLV_TBLENT_LIST) [ ipfw_obj_tentry x N ] 477db785d31SAlexander V. Chernikov * ] 478ac35ff17SAlexander V. Chernikov * 479ac35ff17SAlexander V. Chernikov * Returns 0 on success 480ac35ff17SAlexander V. Chernikov */ 481ac35ff17SAlexander V. Chernikov static int 482db785d31SAlexander V. Chernikov ipfw_manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 483ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 484ac35ff17SAlexander V. Chernikov { 485ac35ff17SAlexander V. Chernikov ipfw_obj_tentry *tent; 486db785d31SAlexander V. Chernikov ipfw_obj_ctlv *ctlv; 487ac35ff17SAlexander V. Chernikov ipfw_obj_header *oh; 488ac35ff17SAlexander V. Chernikov struct tentry_info tei; 489ac35ff17SAlexander V. Chernikov struct tid_info ti; 490ac35ff17SAlexander V. Chernikov int error, read; 491ac35ff17SAlexander V. Chernikov 492ac35ff17SAlexander V. Chernikov /* Check minimum header size */ 493db785d31SAlexander V. Chernikov if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv))) 494ac35ff17SAlexander V. Chernikov return (EINVAL); 495ac35ff17SAlexander V. Chernikov 496ac35ff17SAlexander V. Chernikov /* Check if passed data is too long */ 497ac35ff17SAlexander V. Chernikov if (sd->valsize != sd->kavail) 498ac35ff17SAlexander V. Chernikov return (EINVAL); 499ac35ff17SAlexander V. Chernikov 500ac35ff17SAlexander V. Chernikov oh = (ipfw_obj_header *)sd->kbuf; 501ac35ff17SAlexander V. Chernikov 502ac35ff17SAlexander V. Chernikov /* Basic length checks for TLVs */ 503ac35ff17SAlexander V. Chernikov if (oh->ntlv.head.length != sizeof(oh->ntlv)) 504ac35ff17SAlexander V. Chernikov return (EINVAL); 505ac35ff17SAlexander V. Chernikov 506ac35ff17SAlexander V. Chernikov read = sizeof(*oh); 507ac35ff17SAlexander V. Chernikov 508db785d31SAlexander V. Chernikov ctlv = (ipfw_obj_ctlv *)(oh + 1); 509db785d31SAlexander V. Chernikov if (ctlv->head.length + read != sd->valsize) 510db785d31SAlexander V. Chernikov return (EINVAL); 511db785d31SAlexander V. Chernikov 512db785d31SAlexander V. Chernikov /* 513db785d31SAlexander V. Chernikov * TODO: permit adding multiple entries for given table 514db785d31SAlexander V. Chernikov * at once 515db785d31SAlexander V. Chernikov */ 516db785d31SAlexander V. Chernikov if (ctlv->count != 1) 517db785d31SAlexander V. Chernikov return (EOPNOTSUPP); 518db785d31SAlexander V. Chernikov 519db785d31SAlexander V. Chernikov read += sizeof(*ctlv); 520db785d31SAlexander V. Chernikov 521ac35ff17SAlexander V. Chernikov /* Assume tentry may grow to support larger keys */ 522db785d31SAlexander V. Chernikov tent = (ipfw_obj_tentry *)(ctlv + 1); 523ac35ff17SAlexander V. Chernikov if (tent->head.length < sizeof(*tent) || 524ac35ff17SAlexander V. Chernikov tent->head.length + read > sd->valsize) 525ac35ff17SAlexander V. Chernikov return (EINVAL); 526ac35ff17SAlexander V. Chernikov 52781d3153dSAlexander V. Chernikov /* Convert data into kernel request objects */ 528ac35ff17SAlexander V. Chernikov memset(&tei, 0, sizeof(tei)); 529ac35ff17SAlexander V. Chernikov tei.paddr = &tent->k; 530ac35ff17SAlexander V. Chernikov tei.subtype = tent->subtype; 531ac35ff17SAlexander V. Chernikov tei.masklen = tent->masklen; 53281d3153dSAlexander V. Chernikov if (tent->head.flags & IPFW_TF_UPDATE) 533ac35ff17SAlexander V. Chernikov tei.flags |= TEI_FLAGS_UPDATE; 534ac35ff17SAlexander V. Chernikov tei.value = tent->value; 535ac35ff17SAlexander V. Chernikov 53681d3153dSAlexander V. Chernikov objheader_to_ti(oh, &ti); 537ac35ff17SAlexander V. Chernikov ti.type = oh->ntlv.type; 53881d3153dSAlexander V. Chernikov ti.uidx = tent->idx; 539ac35ff17SAlexander V. Chernikov 540ac35ff17SAlexander V. Chernikov error = (oh->opheader.opcode == IP_FW_TABLE_XADD) ? 5411832a7b3SAlexander V. Chernikov add_table_entry(ch, &ti, &tei) : 5421832a7b3SAlexander V. Chernikov del_table_entry(ch, &ti, &tei); 543ac35ff17SAlexander V. Chernikov 544ac35ff17SAlexander V. Chernikov return (error); 545ac35ff17SAlexander V. Chernikov } 546ac35ff17SAlexander V. Chernikov 54781d3153dSAlexander V. Chernikov /* 54881d3153dSAlexander V. Chernikov * Looks up an entry in given table. 54981d3153dSAlexander V. Chernikov * Data layout (v0)(current): 55081d3153dSAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_obj_tentry ] 55181d3153dSAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_obj_tentry ] 55281d3153dSAlexander V. Chernikov * 55381d3153dSAlexander V. Chernikov * Returns 0 on success 55481d3153dSAlexander V. Chernikov */ 55581d3153dSAlexander V. Chernikov int 55681d3153dSAlexander V. Chernikov ipfw_find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 55781d3153dSAlexander V. Chernikov struct sockopt_data *sd) 55881d3153dSAlexander V. Chernikov { 55981d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 56081d3153dSAlexander V. Chernikov ipfw_obj_header *oh; 56181d3153dSAlexander V. Chernikov struct tid_info ti; 56281d3153dSAlexander V. Chernikov struct table_config *tc; 56381d3153dSAlexander V. Chernikov struct table_algo *ta; 56481d3153dSAlexander V. Chernikov struct table_info *kti; 56581d3153dSAlexander V. Chernikov struct namedobj_instance *ni; 566914bffb6SAlexander V. Chernikov int error; 56781d3153dSAlexander V. Chernikov size_t sz; 56881d3153dSAlexander V. Chernikov 56981d3153dSAlexander V. Chernikov /* Check minimum header size */ 57081d3153dSAlexander V. Chernikov sz = sizeof(*oh) + sizeof(*tent); 57181d3153dSAlexander V. Chernikov if (sd->valsize != sz) 57281d3153dSAlexander V. Chernikov return (EINVAL); 57381d3153dSAlexander V. Chernikov 57481d3153dSAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 57581d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)(oh + 1); 57681d3153dSAlexander V. Chernikov 57781d3153dSAlexander V. Chernikov /* Basic length checks for TLVs */ 57881d3153dSAlexander V. Chernikov if (oh->ntlv.head.length != sizeof(oh->ntlv)) 57981d3153dSAlexander V. Chernikov return (EINVAL); 58081d3153dSAlexander V. Chernikov 58181d3153dSAlexander V. Chernikov objheader_to_ti(oh, &ti); 58281d3153dSAlexander V. Chernikov ti.type = oh->ntlv.type; 58381d3153dSAlexander V. Chernikov ti.uidx = tent->idx; 58481d3153dSAlexander V. Chernikov 58581d3153dSAlexander V. Chernikov IPFW_UH_RLOCK(ch); 58681d3153dSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 58781d3153dSAlexander V. Chernikov 58881d3153dSAlexander V. Chernikov /* 58981d3153dSAlexander V. Chernikov * Find existing table and check its type . 59081d3153dSAlexander V. Chernikov */ 59181d3153dSAlexander V. Chernikov ta = NULL; 59281d3153dSAlexander V. Chernikov if ((tc = find_table(ni, &ti)) == NULL) { 59381d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 59481d3153dSAlexander V. Chernikov return (ESRCH); 59581d3153dSAlexander V. Chernikov } 59681d3153dSAlexander V. Chernikov 59781d3153dSAlexander V. Chernikov /* check table type */ 59881d3153dSAlexander V. Chernikov if (tc->no.type != ti.type) { 59981d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 60081d3153dSAlexander V. Chernikov return (EINVAL); 60181d3153dSAlexander V. Chernikov } 60281d3153dSAlexander V. Chernikov 60381d3153dSAlexander V. Chernikov kti = KIDX_TO_TI(ch, tc->no.kidx); 60481d3153dSAlexander V. Chernikov ta = tc->ta; 60581d3153dSAlexander V. Chernikov 606914bffb6SAlexander V. Chernikov if (ta->find_tentry == NULL) 607914bffb6SAlexander V. Chernikov return (ENOTSUP); 608914bffb6SAlexander V. Chernikov 609914bffb6SAlexander V. Chernikov error = ta->find_tentry(tc->astate, kti, tent); 61081d3153dSAlexander V. Chernikov 61181d3153dSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 61281d3153dSAlexander V. Chernikov 61381d3153dSAlexander V. Chernikov return (error); 61481d3153dSAlexander V. Chernikov } 61581d3153dSAlexander V. Chernikov 616ac35ff17SAlexander V. Chernikov int 617ac35ff17SAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 618ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 619ac35ff17SAlexander V. Chernikov { 620ac35ff17SAlexander V. Chernikov int error; 621ac35ff17SAlexander V. Chernikov struct _ipfw_obj_header *oh; 622ac35ff17SAlexander V. Chernikov struct tid_info ti; 623ac35ff17SAlexander V. Chernikov 624ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh)) 625ac35ff17SAlexander V. Chernikov return (EINVAL); 626ac35ff17SAlexander V. Chernikov 627ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)op3; 628ac35ff17SAlexander V. Chernikov objheader_to_ti(oh, &ti); 629ac35ff17SAlexander V. Chernikov 6301832a7b3SAlexander V. Chernikov if (op3->opcode == IP_FW_TABLE_XDESTROY) 631ac35ff17SAlexander V. Chernikov error = destroy_table(ch, &ti); 6321832a7b3SAlexander V. Chernikov else if (op3->opcode == IP_FW_TABLE_XFLUSH) 633ac35ff17SAlexander V. Chernikov error = flush_table(ch, &ti); 634ac35ff17SAlexander V. Chernikov else 635ac35ff17SAlexander V. Chernikov return (ENOTSUP); 636ac35ff17SAlexander V. Chernikov 637ac35ff17SAlexander V. Chernikov return (error); 6383b3a8eb9SGleb Smirnoff } 6393b3a8eb9SGleb Smirnoff 640b074b7bbSAlexander V. Chernikov /* 6419f7d47b0SAlexander V. Chernikov * Flushes all entries in given table. 642ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 643ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 644ac35ff17SAlexander V. Chernikov * 645ac35ff17SAlexander V. Chernikov * Returns 0 on success 646b074b7bbSAlexander V. Chernikov */ 6471832a7b3SAlexander V. Chernikov int 648ac35ff17SAlexander V. Chernikov flush_table(struct ip_fw_chain *ch, struct tid_info *ti) 6493b3a8eb9SGleb Smirnoff { 650b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 651b074b7bbSAlexander V. Chernikov struct table_config *tc; 6529f7d47b0SAlexander V. Chernikov struct table_algo *ta; 6539f7d47b0SAlexander V. Chernikov struct table_info ti_old, ti_new, *tablestate; 6549f7d47b0SAlexander V. Chernikov void *astate_old, *astate_new; 655914bffb6SAlexander V. Chernikov char algostate[64], *pstate; 656b074b7bbSAlexander V. Chernikov int error; 657b074b7bbSAlexander V. Chernikov uint16_t kidx; 658914bffb6SAlexander V. Chernikov uint8_t tflags; 6593b3a8eb9SGleb Smirnoff 6603b3a8eb9SGleb Smirnoff /* 6619f7d47b0SAlexander V. Chernikov * Stage 1: save table algoritm. 662b074b7bbSAlexander V. Chernikov * Reference found table to ensure it won't disappear. 6633b3a8eb9SGleb Smirnoff */ 664b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 665b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 666b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 667b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 668b074b7bbSAlexander V. Chernikov return (ESRCH); 669b074b7bbSAlexander V. Chernikov } 6709f7d47b0SAlexander V. Chernikov ta = tc->ta; 671b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 672daabb523SAlexander V. Chernikov /* Save statup algo parameters */ 673daabb523SAlexander V. Chernikov if (ta->print_config != NULL) { 674daabb523SAlexander V. Chernikov ta->print_config(tc->astate, KIDX_TO_TI(ch, tc->no.kidx), 675daabb523SAlexander V. Chernikov algostate, sizeof(algostate)); 676daabb523SAlexander V. Chernikov pstate = algostate; 677daabb523SAlexander V. Chernikov } else 678daabb523SAlexander V. Chernikov pstate = NULL; 679914bffb6SAlexander V. Chernikov tflags = tc->tflags; 680b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 6813b3a8eb9SGleb Smirnoff 682b074b7bbSAlexander V. Chernikov /* 6839f7d47b0SAlexander V. Chernikov * Stage 2: allocate new table instance using same algo. 684b074b7bbSAlexander V. Chernikov */ 6859f7d47b0SAlexander V. Chernikov memset(&ti_new, 0, sizeof(struct table_info)); 686914bffb6SAlexander V. Chernikov if ((error = ta->init(ch, &astate_new, &ti_new, pstate, tflags)) != 0) { 687b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 688b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 689b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 690b074b7bbSAlexander V. Chernikov return (error); 691b074b7bbSAlexander V. Chernikov } 692b074b7bbSAlexander V. Chernikov 693b074b7bbSAlexander V. Chernikov /* 694b074b7bbSAlexander V. Chernikov * Stage 3: swap old state pointers with newly-allocated ones. 695b074b7bbSAlexander V. Chernikov * Decrease refcount. 696b074b7bbSAlexander V. Chernikov */ 697b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 698b074b7bbSAlexander V. Chernikov 699b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 700b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 7019f7d47b0SAlexander V. Chernikov tablestate = (struct table_info *)ch->tablestate; 702b074b7bbSAlexander V. Chernikov 7039f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 7049f7d47b0SAlexander V. Chernikov ti_old = tablestate[kidx]; 7059f7d47b0SAlexander V. Chernikov tablestate[kidx] = ti_new; 7069f7d47b0SAlexander V. Chernikov IPFW_WUNLOCK(ch); 707b074b7bbSAlexander V. Chernikov 7089f7d47b0SAlexander V. Chernikov astate_old = tc->astate; 7099f7d47b0SAlexander V. Chernikov tc->astate = astate_new; 7109f7d47b0SAlexander V. Chernikov tc->ti = ti_new; 7119f7d47b0SAlexander V. Chernikov tc->count = 0; 712b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 713b074b7bbSAlexander V. Chernikov 714b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 7153b3a8eb9SGleb Smirnoff 716b074b7bbSAlexander V. Chernikov /* 717b074b7bbSAlexander V. Chernikov * Stage 4: perform real flush. 718b074b7bbSAlexander V. Chernikov */ 7199f7d47b0SAlexander V. Chernikov ta->destroy(astate_old, &ti_old); 7203b3a8eb9SGleb Smirnoff 7213b3a8eb9SGleb Smirnoff return (0); 7223b3a8eb9SGleb Smirnoff } 7233b3a8eb9SGleb Smirnoff 724b074b7bbSAlexander V. Chernikov /* 7259f7d47b0SAlexander V. Chernikov * Destroys table specified by @ti. 726ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 727ac35ff17SAlexander V. Chernikov * Request: [ ip_fw3_opheader ] 728ac35ff17SAlexander V. Chernikov * 729ac35ff17SAlexander V. Chernikov * Returns 0 on success 730b074b7bbSAlexander V. Chernikov */ 731ac35ff17SAlexander V. Chernikov static int 732ac35ff17SAlexander V. Chernikov destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) 733b074b7bbSAlexander V. Chernikov { 734b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 735b074b7bbSAlexander V. Chernikov struct table_config *tc; 736b074b7bbSAlexander V. Chernikov 737b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 738b074b7bbSAlexander V. Chernikov 739b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 740b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 741b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 742b074b7bbSAlexander V. Chernikov return (ESRCH); 743b074b7bbSAlexander V. Chernikov } 744b074b7bbSAlexander V. Chernikov 7459f7d47b0SAlexander V. Chernikov /* Do not permit destroying referenced tables */ 7469f7d47b0SAlexander V. Chernikov if (tc->no.refcnt > 0) { 747b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 748b074b7bbSAlexander V. Chernikov return (EBUSY); 749b074b7bbSAlexander V. Chernikov } 750b074b7bbSAlexander V. Chernikov 751b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 752b074b7bbSAlexander V. Chernikov unlink_table(ch, tc); 753b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 754b074b7bbSAlexander V. Chernikov 755b074b7bbSAlexander V. Chernikov /* Free obj index */ 756ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0) 757b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 758b074b7bbSAlexander V. Chernikov tc->no.kidx, tc->tablename); 759b074b7bbSAlexander V. Chernikov 760b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 761b074b7bbSAlexander V. Chernikov 762b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 763b074b7bbSAlexander V. Chernikov 764b074b7bbSAlexander V. Chernikov return (0); 765b074b7bbSAlexander V. Chernikov } 766b074b7bbSAlexander V. Chernikov 767b074b7bbSAlexander V. Chernikov static void 768b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, 769b074b7bbSAlexander V. Chernikov void *arg) 770b074b7bbSAlexander V. Chernikov { 771b074b7bbSAlexander V. Chernikov 772b074b7bbSAlexander V. Chernikov unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); 773ac35ff17SAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, no->kidx) != 0) 774b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 775b074b7bbSAlexander V. Chernikov no->kidx, no->name); 776b074b7bbSAlexander V. Chernikov free_table_config(ni, (struct table_config *)no); 777b074b7bbSAlexander V. Chernikov } 778b074b7bbSAlexander V. Chernikov 7793b3a8eb9SGleb Smirnoff void 7803b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch) 7813b3a8eb9SGleb Smirnoff { 7823b3a8eb9SGleb Smirnoff 783b074b7bbSAlexander V. Chernikov /* Remove all tables from working set */ 784b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 785b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 786b074b7bbSAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); 787b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 788b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 7893b3a8eb9SGleb Smirnoff 7903b3a8eb9SGleb Smirnoff /* Free pointers itself */ 7919f7d47b0SAlexander V. Chernikov free(ch->tablestate, M_IPFW); 7929f7d47b0SAlexander V. Chernikov 7939f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(ch); 794b074b7bbSAlexander V. Chernikov 795b074b7bbSAlexander V. Chernikov ipfw_objhash_destroy(CHAIN_TO_NI(ch)); 796b074b7bbSAlexander V. Chernikov free(CHAIN_TO_TCFG(ch), M_IPFW); 7973b3a8eb9SGleb Smirnoff } 7983b3a8eb9SGleb Smirnoff 7993b3a8eb9SGleb Smirnoff int 8003b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch) 8013b3a8eb9SGleb Smirnoff { 802b074b7bbSAlexander V. Chernikov struct tables_config *tcfg; 803b074b7bbSAlexander V. Chernikov 8043b3a8eb9SGleb Smirnoff /* Allocate pointers */ 8059f7d47b0SAlexander V. Chernikov ch->tablestate = malloc(V_fw_tables_max * sizeof(struct table_info), 8069f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 807b074b7bbSAlexander V. Chernikov 808b074b7bbSAlexander V. Chernikov tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); 809b074b7bbSAlexander V. Chernikov tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); 810b074b7bbSAlexander V. Chernikov ch->tblcfg = tcfg; 811b074b7bbSAlexander V. Chernikov 8129f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(ch); 8139f7d47b0SAlexander V. Chernikov 8143b3a8eb9SGleb Smirnoff return (0); 8153b3a8eb9SGleb Smirnoff } 8163b3a8eb9SGleb Smirnoff 8173b3a8eb9SGleb Smirnoff int 8183b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) 8193b3a8eb9SGleb Smirnoff { 8203b3a8eb9SGleb Smirnoff unsigned int ntables_old, tbl; 821b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 8229f7d47b0SAlexander V. Chernikov void *new_idx, *old_tablestate, *tablestate; 82368394ec8SAlexander V. Chernikov struct table_info *ti; 82468394ec8SAlexander V. Chernikov struct table_config *tc; 82568394ec8SAlexander V. Chernikov int i, new_blocks; 8263b3a8eb9SGleb Smirnoff 8273b3a8eb9SGleb Smirnoff /* Check new value for validity */ 8283b3a8eb9SGleb Smirnoff if (ntables > IPFW_TABLES_MAX) 8293b3a8eb9SGleb Smirnoff ntables = IPFW_TABLES_MAX; 8303b3a8eb9SGleb Smirnoff 8313b3a8eb9SGleb Smirnoff /* Allocate new pointers */ 8329f7d47b0SAlexander V. Chernikov tablestate = malloc(ntables * sizeof(struct table_info), 8339f7d47b0SAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 8349f7d47b0SAlexander V. Chernikov 835b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); 8363b3a8eb9SGleb Smirnoff 8379f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 8383b3a8eb9SGleb Smirnoff 8393b3a8eb9SGleb Smirnoff tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables; 840b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 841b074b7bbSAlexander V. Chernikov 8429f7d47b0SAlexander V. Chernikov /* Temporary restrict decreasing max_tables */ 8439f7d47b0SAlexander V. Chernikov if (ntables < V_fw_tables_max) { 8449f7d47b0SAlexander V. Chernikov 8459f7d47b0SAlexander V. Chernikov /* 8469f7d47b0SAlexander V. Chernikov * FIXME: Check if we really can shrink 8479f7d47b0SAlexander V. Chernikov */ 8489f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 849b074b7bbSAlexander V. Chernikov return (EINVAL); 850b074b7bbSAlexander V. Chernikov } 8513b3a8eb9SGleb Smirnoff 8529f7d47b0SAlexander V. Chernikov /* Copy table info/indices */ 8539f7d47b0SAlexander V. Chernikov memcpy(tablestate, ch->tablestate, sizeof(struct table_info) * tbl); 8549f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks); 8553b3a8eb9SGleb Smirnoff 8569f7d47b0SAlexander V. Chernikov IPFW_WLOCK(ch); 8579f7d47b0SAlexander V. Chernikov 8589f7d47b0SAlexander V. Chernikov /* Change pointers */ 8599f7d47b0SAlexander V. Chernikov old_tablestate = ch->tablestate; 8609f7d47b0SAlexander V. Chernikov ch->tablestate = tablestate; 8619f7d47b0SAlexander V. Chernikov ipfw_objhash_bitmap_swap(ni, &new_idx, &new_blocks); 8623b3a8eb9SGleb Smirnoff 8633b3a8eb9SGleb Smirnoff ntables_old = V_fw_tables_max; 8643b3a8eb9SGleb Smirnoff V_fw_tables_max = ntables; 8653b3a8eb9SGleb Smirnoff 8663b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 86768394ec8SAlexander V. Chernikov 86868394ec8SAlexander V. Chernikov /* Notify all consumers that their @ti pointer has changed */ 86968394ec8SAlexander V. Chernikov ti = (struct table_info *)ch->tablestate; 87068394ec8SAlexander V. Chernikov for (i = 0; i < tbl; i++, ti++) { 87168394ec8SAlexander V. Chernikov if (ti->lookup == NULL) 87268394ec8SAlexander V. Chernikov continue; 87368394ec8SAlexander V. Chernikov tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, i); 87468394ec8SAlexander V. Chernikov if (tc == NULL || tc->ta->change_ti == NULL) 87568394ec8SAlexander V. Chernikov continue; 87668394ec8SAlexander V. Chernikov 87768394ec8SAlexander V. Chernikov tc->ta->change_ti(tc->astate, ti); 87868394ec8SAlexander V. Chernikov } 87968394ec8SAlexander V. Chernikov 8809f7d47b0SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 8813b3a8eb9SGleb Smirnoff 8823b3a8eb9SGleb Smirnoff /* Free old pointers */ 8839f7d47b0SAlexander V. Chernikov free(old_tablestate, M_IPFW); 884b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 8853b3a8eb9SGleb Smirnoff 8863b3a8eb9SGleb Smirnoff return (0); 8873b3a8eb9SGleb Smirnoff } 8883b3a8eb9SGleb Smirnoff 8893b3a8eb9SGleb Smirnoff int 8903b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 8913b3a8eb9SGleb Smirnoff uint32_t *val) 8923b3a8eb9SGleb Smirnoff { 8939f7d47b0SAlexander V. Chernikov struct table_info *ti; 8943b3a8eb9SGleb Smirnoff 8959f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 8969f7d47b0SAlexander V. Chernikov 8979f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, &addr, sizeof(in_addr_t), val)); 8983b3a8eb9SGleb Smirnoff } 8999f7d47b0SAlexander V. Chernikov 9009f7d47b0SAlexander V. Chernikov int 9019f7d47b0SAlexander V. Chernikov ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, 9029f7d47b0SAlexander V. Chernikov void *paddr, uint32_t *val) 9039f7d47b0SAlexander V. Chernikov { 9049f7d47b0SAlexander V. Chernikov struct table_info *ti; 9059f7d47b0SAlexander V. Chernikov 9069f7d47b0SAlexander V. Chernikov ti = &(((struct table_info *)ch->tablestate)[tbl]); 9079f7d47b0SAlexander V. Chernikov 9089f7d47b0SAlexander V. Chernikov return (ti->lookup(ti, paddr, plen, val)); 9099f7d47b0SAlexander V. Chernikov } 9109f7d47b0SAlexander V. Chernikov 9119f7d47b0SAlexander V. Chernikov /* 9129f7d47b0SAlexander V. Chernikov * Info/List/dump support for tables. 9139f7d47b0SAlexander V. Chernikov * 9149f7d47b0SAlexander V. Chernikov */ 9159f7d47b0SAlexander V. Chernikov 916f1220db8SAlexander V. Chernikov /* 917d3a4f924SAlexander V. Chernikov * High-level 'get' cmds sysctl handlers 918d3a4f924SAlexander V. Chernikov */ 919d3a4f924SAlexander V. Chernikov 920d3a4f924SAlexander V. Chernikov /* 921d3a4f924SAlexander V. Chernikov * Get buffer size needed to list info for all tables. 922ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 923d3a4f924SAlexander V. Chernikov * Request: [ empty ], size = sizeof(ipfw_obj_lheader) 924d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ] 925d3a4f924SAlexander V. Chernikov * 926d3a4f924SAlexander V. Chernikov * Returns 0 on success 927f1220db8SAlexander V. Chernikov */ 928f1220db8SAlexander V. Chernikov int 9292d99a349SAlexander V. Chernikov ipfw_listsize_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 930f1220db8SAlexander V. Chernikov { 931f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 932f1220db8SAlexander V. Chernikov 9332d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 9342d99a349SAlexander V. Chernikov if (olh == NULL) 935d3a4f924SAlexander V. Chernikov return (EINVAL); 936d3a4f924SAlexander V. Chernikov 937f1220db8SAlexander V. Chernikov olh->size = sizeof(*olh); /* Make export_table store needed size */ 938f1220db8SAlexander V. Chernikov 939f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 9402d99a349SAlexander V. Chernikov export_tables(ch, olh, sd); 941f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 942f1220db8SAlexander V. Chernikov 9432d99a349SAlexander V. Chernikov return (0); 944f1220db8SAlexander V. Chernikov } 945f1220db8SAlexander V. Chernikov 946d3a4f924SAlexander V. Chernikov /* 947d3a4f924SAlexander V. Chernikov * Lists all tables currently available in kernel. 948ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 949d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 950d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_xtable_info x N ] 951d3a4f924SAlexander V. Chernikov * 952d3a4f924SAlexander V. Chernikov * Returns 0 on success 953d3a4f924SAlexander V. Chernikov */ 954f1220db8SAlexander V. Chernikov int 9552d99a349SAlexander V. Chernikov ipfw_list_tables(struct ip_fw_chain *ch, struct sockopt_data *sd) 956f1220db8SAlexander V. Chernikov { 957f1220db8SAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 958f1220db8SAlexander V. Chernikov int error; 959f1220db8SAlexander V. Chernikov 9602d99a349SAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 9612d99a349SAlexander V. Chernikov if (olh == NULL) 962d3a4f924SAlexander V. Chernikov return (EINVAL); 96368394ec8SAlexander V. Chernikov if (sd->valsize < olh->size) 96468394ec8SAlexander V. Chernikov return (EINVAL); 965d3a4f924SAlexander V. Chernikov 966f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 9672d99a349SAlexander V. Chernikov error = export_tables(ch, olh, sd); 968f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 969f1220db8SAlexander V. Chernikov 970f1220db8SAlexander V. Chernikov return (error); 971f1220db8SAlexander V. Chernikov } 972f1220db8SAlexander V. Chernikov 973f1220db8SAlexander V. Chernikov /* 9742d99a349SAlexander V. Chernikov * Store table info to buffer provided by @sd. 975ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 976d3a4f924SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info(empty)] 977d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ] 978d3a4f924SAlexander V. Chernikov * 979d3a4f924SAlexander V. Chernikov * Returns 0 on success. 980d3a4f924SAlexander V. Chernikov */ 981d3a4f924SAlexander V. Chernikov int 9822d99a349SAlexander V. Chernikov ipfw_describe_table(struct ip_fw_chain *ch, struct sockopt_data *sd) 983d3a4f924SAlexander V. Chernikov { 984d3a4f924SAlexander V. Chernikov struct _ipfw_obj_header *oh; 985d3a4f924SAlexander V. Chernikov struct table_config *tc; 986d3a4f924SAlexander V. Chernikov struct tid_info ti; 987d3a4f924SAlexander V. Chernikov size_t sz; 988d3a4f924SAlexander V. Chernikov 989d3a4f924SAlexander V. Chernikov sz = sizeof(*oh) + sizeof(ipfw_xtable_info); 9902d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 9912d99a349SAlexander V. Chernikov if (oh == NULL) 992d3a4f924SAlexander V. Chernikov return (EINVAL); 993d3a4f924SAlexander V. Chernikov 994d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 995d3a4f924SAlexander V. Chernikov 996d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 997d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 998d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 999d3a4f924SAlexander V. Chernikov return (ESRCH); 1000d3a4f924SAlexander V. Chernikov } 1001d3a4f924SAlexander V. Chernikov 1002ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, (ipfw_xtable_info *)(oh + 1)); 1003d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1004d3a4f924SAlexander V. Chernikov 10052d99a349SAlexander V. Chernikov return (0); 1006d3a4f924SAlexander V. Chernikov } 1007d3a4f924SAlexander V. Chernikov 1008f1220db8SAlexander V. Chernikov struct dump_args { 1009f1220db8SAlexander V. Chernikov struct table_info *ti; 1010f1220db8SAlexander V. Chernikov struct table_config *tc; 10112d99a349SAlexander V. Chernikov struct sockopt_data *sd; 1012f1220db8SAlexander V. Chernikov uint32_t cnt; 1013f1220db8SAlexander V. Chernikov uint16_t uidx; 101481d3153dSAlexander V. Chernikov int error; 10152d99a349SAlexander V. Chernikov ipfw_table_entry *ent; 10162d99a349SAlexander V. Chernikov uint32_t size; 101781d3153dSAlexander V. Chernikov ipfw_obj_tentry tent; 1018f1220db8SAlexander V. Chernikov }; 1019f1220db8SAlexander V. Chernikov 1020f1220db8SAlexander V. Chernikov int 10212d99a349SAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 10222d99a349SAlexander V. Chernikov struct sockopt_data *sd) 1023f1220db8SAlexander V. Chernikov { 1024d3a4f924SAlexander V. Chernikov int error; 1025d3a4f924SAlexander V. Chernikov 1026d3a4f924SAlexander V. Chernikov switch (op3->version) { 1027d3a4f924SAlexander V. Chernikov case 0: 10282d99a349SAlexander V. Chernikov error = ipfw_dump_table_v0(ch, sd); 1029d3a4f924SAlexander V. Chernikov break; 1030d3a4f924SAlexander V. Chernikov case 1: 10312d99a349SAlexander V. Chernikov error = ipfw_dump_table_v1(ch, sd); 1032d3a4f924SAlexander V. Chernikov break; 1033d3a4f924SAlexander V. Chernikov default: 1034d3a4f924SAlexander V. Chernikov error = ENOTSUP; 1035d3a4f924SAlexander V. Chernikov } 1036d3a4f924SAlexander V. Chernikov 1037d3a4f924SAlexander V. Chernikov return (error); 1038d3a4f924SAlexander V. Chernikov } 1039d3a4f924SAlexander V. Chernikov 1040d3a4f924SAlexander V. Chernikov /* 1041d3a4f924SAlexander V. Chernikov * Dumps all table data 1042ac35ff17SAlexander V. Chernikov * Data layout (v1)(current): 10432d99a349SAlexander V. Chernikov * Request: [ ipfw_obj_header ], size = ipfw_xtable_info.size 104481d3153dSAlexander V. Chernikov * Reply: [ ipfw_obj_header ipfw_xtable_info ipfw_obj_tentry x N ] 1045d3a4f924SAlexander V. Chernikov * 1046d3a4f924SAlexander V. Chernikov * Returns 0 on success 1047d3a4f924SAlexander V. Chernikov */ 1048d3a4f924SAlexander V. Chernikov static int 10492d99a349SAlexander V. Chernikov ipfw_dump_table_v1(struct ip_fw_chain *ch, struct sockopt_data *sd) 1050d3a4f924SAlexander V. Chernikov { 1051f1220db8SAlexander V. Chernikov struct _ipfw_obj_header *oh; 1052f1220db8SAlexander V. Chernikov ipfw_xtable_info *i; 1053f1220db8SAlexander V. Chernikov struct tid_info ti; 1054f1220db8SAlexander V. Chernikov struct table_config *tc; 1055f1220db8SAlexander V. Chernikov struct table_algo *ta; 1056f1220db8SAlexander V. Chernikov struct dump_args da; 1057d3a4f924SAlexander V. Chernikov uint32_t sz; 1058f1220db8SAlexander V. Chernikov 10592d99a349SAlexander V. Chernikov sz = sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 10602d99a349SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 10612d99a349SAlexander V. Chernikov if (oh == NULL) 1062d3a4f924SAlexander V. Chernikov return (EINVAL); 1063d3a4f924SAlexander V. Chernikov 10642d99a349SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 1065d3a4f924SAlexander V. Chernikov objheader_to_ti(oh, &ti); 1066f1220db8SAlexander V. Chernikov 1067f1220db8SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 1068f1220db8SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 1069f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1070f1220db8SAlexander V. Chernikov return (ESRCH); 1071f1220db8SAlexander V. Chernikov } 1072ac35ff17SAlexander V. Chernikov export_table_info(ch, tc, i); 10732d99a349SAlexander V. Chernikov sz = tc->count; 10742d99a349SAlexander V. Chernikov 107581d3153dSAlexander V. Chernikov if (sd->valsize < sz + tc->count * sizeof(ipfw_obj_tentry)) { 10762d99a349SAlexander V. Chernikov 10772d99a349SAlexander V. Chernikov /* 10782d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 10792d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 10802d99a349SAlexander V. Chernikov * relevant table info including size, so we 10812d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 10822d99a349SAlexander V. Chernikov */ 1083f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 10842d99a349SAlexander V. Chernikov return (ENOMEM); 1085f1220db8SAlexander V. Chernikov } 1086f1220db8SAlexander V. Chernikov 1087f1220db8SAlexander V. Chernikov /* 1088f1220db8SAlexander V. Chernikov * Do the actual dump in eXtended format 1089f1220db8SAlexander V. Chernikov */ 1090d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 1091f1220db8SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 1092f1220db8SAlexander V. Chernikov da.tc = tc; 10932d99a349SAlexander V. Chernikov da.sd = sd; 1094f1220db8SAlexander V. Chernikov 1095f1220db8SAlexander V. Chernikov ta = tc->ta; 1096f1220db8SAlexander V. Chernikov 109781d3153dSAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_tentry, &da); 1098f1220db8SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1099f1220db8SAlexander V. Chernikov 110081d3153dSAlexander V. Chernikov return (da.error); 1101f1220db8SAlexander V. Chernikov } 1102f1220db8SAlexander V. Chernikov 1103d3a4f924SAlexander V. Chernikov /* 1104d3a4f924SAlexander V. Chernikov * Dumps all table data 11052d99a349SAlexander V. Chernikov * Data layout (version 0)(legacy): 1106d3a4f924SAlexander V. Chernikov * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE() 1107d3a4f924SAlexander V. Chernikov * Reply: [ ipfw_xtable ipfw_table_xentry x N ] 1108d3a4f924SAlexander V. Chernikov * 1109d3a4f924SAlexander V. Chernikov * Returns 0 on success 1110d3a4f924SAlexander V. Chernikov */ 1111d3a4f924SAlexander V. Chernikov static int 11122d99a349SAlexander V. Chernikov ipfw_dump_table_v0(struct ip_fw_chain *ch, struct sockopt_data *sd) 1113d3a4f924SAlexander V. Chernikov { 1114d3a4f924SAlexander V. Chernikov ipfw_xtable *xtbl; 1115d3a4f924SAlexander V. Chernikov struct tid_info ti; 1116d3a4f924SAlexander V. Chernikov struct table_config *tc; 1117d3a4f924SAlexander V. Chernikov struct table_algo *ta; 1118d3a4f924SAlexander V. Chernikov struct dump_args da; 1119d3a4f924SAlexander V. Chernikov size_t sz; 1120d3a4f924SAlexander V. Chernikov 11212d99a349SAlexander V. Chernikov xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable)); 11222d99a349SAlexander V. Chernikov if (xtbl == NULL) 1123d3a4f924SAlexander V. Chernikov return (EINVAL); 1124d3a4f924SAlexander V. Chernikov 1125d3a4f924SAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 1126d3a4f924SAlexander V. Chernikov ti.uidx = xtbl->tbl; 1127d3a4f924SAlexander V. Chernikov 1128d3a4f924SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 1129d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { 1130d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1131d3a4f924SAlexander V. Chernikov return (0); 1132d3a4f924SAlexander V. Chernikov } 1133d3a4f924SAlexander V. Chernikov sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); 11342d99a349SAlexander V. Chernikov 11352d99a349SAlexander V. Chernikov xtbl->cnt = tc->count; 11362d99a349SAlexander V. Chernikov xtbl->size = sz; 11372d99a349SAlexander V. Chernikov xtbl->type = tc->no.type; 11382d99a349SAlexander V. Chernikov xtbl->tbl = ti.uidx; 11392d99a349SAlexander V. Chernikov 11402d99a349SAlexander V. Chernikov if (sd->valsize < sz) { 11412d99a349SAlexander V. Chernikov 11422d99a349SAlexander V. Chernikov /* 11432d99a349SAlexander V. Chernikov * Submitted buffer size is not enough. 11442d99a349SAlexander V. Chernikov * WE've already filled in @i structure with 11452d99a349SAlexander V. Chernikov * relevant table info including size, so we 11462d99a349SAlexander V. Chernikov * can return. Buffer will be flushed automatically. 11472d99a349SAlexander V. Chernikov */ 1148d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 11492d99a349SAlexander V. Chernikov return (ENOMEM); 1150d3a4f924SAlexander V. Chernikov } 1151d3a4f924SAlexander V. Chernikov 1152d3a4f924SAlexander V. Chernikov /* Do the actual dump in eXtended format */ 1153d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 1154d3a4f924SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 1155d3a4f924SAlexander V. Chernikov da.tc = tc; 11562d99a349SAlexander V. Chernikov da.sd = sd; 11572d99a349SAlexander V. Chernikov 1158d3a4f924SAlexander V. Chernikov ta = tc->ta; 1159d3a4f924SAlexander V. Chernikov 1160d3a4f924SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); 1161d3a4f924SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 1162d3a4f924SAlexander V. Chernikov 11632d99a349SAlexander V. Chernikov return (0); 1164d3a4f924SAlexander V. Chernikov } 1165d3a4f924SAlexander V. Chernikov 1166d3a4f924SAlexander V. Chernikov /* 11679490a627SAlexander V. Chernikov * Creates new table. 1168ac35ff17SAlexander V. Chernikov * Data layout (v0)(current): 11699490a627SAlexander V. Chernikov * Request: [ ipfw_obj_header ipfw_xtable_info ] 11709490a627SAlexander V. Chernikov * 11719490a627SAlexander V. Chernikov * Returns 0 on success 11729490a627SAlexander V. Chernikov */ 11739490a627SAlexander V. Chernikov int 1174ac35ff17SAlexander V. Chernikov ipfw_create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 1175ac35ff17SAlexander V. Chernikov struct sockopt_data *sd) 11769490a627SAlexander V. Chernikov { 11779490a627SAlexander V. Chernikov struct _ipfw_obj_header *oh; 11789490a627SAlexander V. Chernikov ipfw_xtable_info *i; 11799490a627SAlexander V. Chernikov char *tname, *aname; 11809490a627SAlexander V. Chernikov struct tid_info ti; 11819490a627SAlexander V. Chernikov struct namedobj_instance *ni; 11829490a627SAlexander V. Chernikov struct table_config *tc; 11839490a627SAlexander V. Chernikov 1184ac35ff17SAlexander V. Chernikov if (sd->valsize != sizeof(*oh) + sizeof(ipfw_xtable_info)) 11859490a627SAlexander V. Chernikov return (EINVAL); 11869490a627SAlexander V. Chernikov 1187ac35ff17SAlexander V. Chernikov oh = (struct _ipfw_obj_header *)sd->kbuf; 11889490a627SAlexander V. Chernikov i = (ipfw_xtable_info *)(oh + 1); 11899490a627SAlexander V. Chernikov 11909490a627SAlexander V. Chernikov /* 11919490a627SAlexander V. Chernikov * Verify user-supplied strings. 11922d99a349SAlexander V. Chernikov * Check for null-terminated/zero-length strings/ 11939490a627SAlexander V. Chernikov */ 1194ac35ff17SAlexander V. Chernikov tname = oh->ntlv.name; 11959490a627SAlexander V. Chernikov aname = i->algoname; 1196ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(tname) != 0 || 11979490a627SAlexander V. Chernikov strnlen(aname, sizeof(i->algoname)) == sizeof(i->algoname)) 11989490a627SAlexander V. Chernikov return (EINVAL); 11999490a627SAlexander V. Chernikov 12009490a627SAlexander V. Chernikov if (aname[0] == '\0') { 12019490a627SAlexander V. Chernikov /* Use default algorithm */ 12029490a627SAlexander V. Chernikov aname = NULL; 12039490a627SAlexander V. Chernikov } 12049490a627SAlexander V. Chernikov 12059490a627SAlexander V. Chernikov objheader_to_ti(oh, &ti); 1206ac35ff17SAlexander V. Chernikov ti.type = i->type; 12079490a627SAlexander V. Chernikov 12089490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 12099490a627SAlexander V. Chernikov 12109490a627SAlexander V. Chernikov IPFW_UH_RLOCK(ch); 12119490a627SAlexander V. Chernikov if ((tc = find_table(ni, &ti)) != NULL) { 12129490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 12139490a627SAlexander V. Chernikov return (EEXIST); 12149490a627SAlexander V. Chernikov } 12159490a627SAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 12169490a627SAlexander V. Chernikov 12174c0c07a5SAlexander V. Chernikov return (create_table_internal(ch, &ti, aname, i)); 1218db785d31SAlexander V. Chernikov } 1219db785d31SAlexander V. Chernikov 1220db785d31SAlexander V. Chernikov /* 1221db785d31SAlexander V. Chernikov * Creates new table based on @ti and @aname. 1222db785d31SAlexander V. Chernikov * 1223db785d31SAlexander V. Chernikov * Relies on table name checking inside find_name_tlv() 1224db785d31SAlexander V. Chernikov * Assume @aname to be checked and valid. 1225db785d31SAlexander V. Chernikov * 1226db785d31SAlexander V. Chernikov * Returns 0 on success. 1227db785d31SAlexander V. Chernikov */ 1228db785d31SAlexander V. Chernikov static int 1229db785d31SAlexander V. Chernikov create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, 12304c0c07a5SAlexander V. Chernikov char *aname, ipfw_xtable_info *i) 1231db785d31SAlexander V. Chernikov { 1232db785d31SAlexander V. Chernikov struct namedobj_instance *ni; 1233db785d31SAlexander V. Chernikov struct table_config *tc; 1234db785d31SAlexander V. Chernikov struct table_algo *ta; 1235db785d31SAlexander V. Chernikov uint16_t kidx; 1236db785d31SAlexander V. Chernikov 1237db785d31SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1238db785d31SAlexander V. Chernikov 1239db785d31SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(ch), ti, aname); 12409490a627SAlexander V. Chernikov if (ta == NULL) 12419490a627SAlexander V. Chernikov return (ENOTSUP); 12429490a627SAlexander V. Chernikov 12434c0c07a5SAlexander V. Chernikov tc = alloc_table_config(ch, ti, ta, aname, i->tflags, i->vtype); 12444c0c07a5SAlexander V. Chernikov if (tc == NULL) 12459490a627SAlexander V. Chernikov return (ENOMEM); 12469490a627SAlexander V. Chernikov 12474c0c07a5SAlexander V. Chernikov tc->limit = i->limit; 12484c0c07a5SAlexander V. Chernikov 12499490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 1250db785d31SAlexander V. Chernikov 1251db785d31SAlexander V. Chernikov /* Check if table has been already created */ 1252db785d31SAlexander V. Chernikov if (find_table(ni, ti) != NULL) { 1253db785d31SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1254db785d31SAlexander V. Chernikov free_table_config(ni, tc); 1255db785d31SAlexander V. Chernikov return (EEXIST); 1256db785d31SAlexander V. Chernikov } 1257db785d31SAlexander V. Chernikov 1258ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &kidx) != 0) { 12599490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 1260db785d31SAlexander V. Chernikov printf("Unable to allocate table index." 1261db785d31SAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max"); 12629490a627SAlexander V. Chernikov free_table_config(ni, tc); 12639490a627SAlexander V. Chernikov return (EBUSY); 12649490a627SAlexander V. Chernikov } 12659490a627SAlexander V. Chernikov 12669490a627SAlexander V. Chernikov tc->no.kidx = kidx; 12679490a627SAlexander V. Chernikov 12689490a627SAlexander V. Chernikov IPFW_WLOCK(ch); 12699490a627SAlexander V. Chernikov link_table(ch, tc); 12709490a627SAlexander V. Chernikov IPFW_WUNLOCK(ch); 12719490a627SAlexander V. Chernikov 12729490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 12739490a627SAlexander V. Chernikov 12749490a627SAlexander V. Chernikov return (0); 12759490a627SAlexander V. Chernikov } 12769490a627SAlexander V. Chernikov 1277d3a4f924SAlexander V. Chernikov void 1278d3a4f924SAlexander V. Chernikov objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti) 1279d3a4f924SAlexander V. Chernikov { 1280d3a4f924SAlexander V. Chernikov 1281d3a4f924SAlexander V. Chernikov memset(ti, 0, sizeof(struct tid_info)); 128281d3153dSAlexander V. Chernikov ti->set = oh->ntlv.set; 1283d3a4f924SAlexander V. Chernikov ti->uidx = oh->idx; 1284d3a4f924SAlexander V. Chernikov ti->tlvs = &oh->ntlv; 1285d3a4f924SAlexander V. Chernikov ti->tlen = oh->ntlv.head.length; 1286d3a4f924SAlexander V. Chernikov } 1287d3a4f924SAlexander V. Chernikov 1288563b5ab1SAlexander V. Chernikov int 1289563b5ab1SAlexander V. Chernikov ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx, 1290563b5ab1SAlexander V. Chernikov struct sockopt_data *sd) 1291563b5ab1SAlexander V. Chernikov { 1292563b5ab1SAlexander V. Chernikov struct namedobj_instance *ni; 1293563b5ab1SAlexander V. Chernikov struct named_object *no; 1294563b5ab1SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1295563b5ab1SAlexander V. Chernikov 1296563b5ab1SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 1297563b5ab1SAlexander V. Chernikov 1298ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 1299563b5ab1SAlexander V. Chernikov KASSERT(no != NULL, ("invalid table kidx passed")); 1300563b5ab1SAlexander V. Chernikov 1301563b5ab1SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 1302563b5ab1SAlexander V. Chernikov if (ntlv == NULL) 1303563b5ab1SAlexander V. Chernikov return (ENOMEM); 1304563b5ab1SAlexander V. Chernikov 1305563b5ab1SAlexander V. Chernikov ntlv->head.type = IPFW_TLV_TBL_NAME; 1306563b5ab1SAlexander V. Chernikov ntlv->head.length = sizeof(*ntlv); 1307563b5ab1SAlexander V. Chernikov ntlv->idx = no->kidx; 1308563b5ab1SAlexander V. Chernikov strlcpy(ntlv->name, no->name, sizeof(ntlv->name)); 1309563b5ab1SAlexander V. Chernikov 1310563b5ab1SAlexander V. Chernikov return (0); 1311563b5ab1SAlexander V. Chernikov } 1312563b5ab1SAlexander V. Chernikov 13139f7d47b0SAlexander V. Chernikov static void 1314ac35ff17SAlexander V. Chernikov export_table_info(struct ip_fw_chain *ch, struct table_config *tc, 1315ac35ff17SAlexander V. Chernikov ipfw_xtable_info *i) 13169f7d47b0SAlexander V. Chernikov { 1317ac35ff17SAlexander V. Chernikov struct table_info *ti; 13189f7d47b0SAlexander V. Chernikov 13199f7d47b0SAlexander V. Chernikov i->type = tc->no.type; 1320914bffb6SAlexander V. Chernikov i->tflags = tc->tflags; 1321ac35ff17SAlexander V. Chernikov i->vtype = tc->vtype; 13229f7d47b0SAlexander V. Chernikov i->set = tc->no.set; 13239f7d47b0SAlexander V. Chernikov i->kidx = tc->no.kidx; 13249f7d47b0SAlexander V. Chernikov i->refcnt = tc->no.refcnt; 13259f7d47b0SAlexander V. Chernikov i->count = tc->count; 13264c0c07a5SAlexander V. Chernikov i->limit = tc->limit; 132781d3153dSAlexander V. Chernikov i->size = tc->count * sizeof(ipfw_obj_tentry); 1328f1220db8SAlexander V. Chernikov i->size += sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info); 13299f7d47b0SAlexander V. Chernikov strlcpy(i->tablename, tc->tablename, sizeof(i->tablename)); 1330ac35ff17SAlexander V. Chernikov if (tc->ta->print_config != NULL) { 1331ac35ff17SAlexander V. Chernikov /* Use algo function to print table config to string */ 1332ac35ff17SAlexander V. Chernikov ti = KIDX_TO_TI(ch, tc->no.kidx); 1333ac35ff17SAlexander V. Chernikov tc->ta->print_config(tc->astate, ti, i->algoname, 1334ac35ff17SAlexander V. Chernikov sizeof(i->algoname)); 1335ac35ff17SAlexander V. Chernikov } else 1336ac35ff17SAlexander V. Chernikov strlcpy(i->algoname, tc->ta->name, sizeof(i->algoname)); 13379f7d47b0SAlexander V. Chernikov } 13389f7d47b0SAlexander V. Chernikov 1339ac35ff17SAlexander V. Chernikov struct dump_table_args { 1340ac35ff17SAlexander V. Chernikov struct ip_fw_chain *ch; 1341ac35ff17SAlexander V. Chernikov struct sockopt_data *sd; 1342ac35ff17SAlexander V. Chernikov }; 1343ac35ff17SAlexander V. Chernikov 13449f7d47b0SAlexander V. Chernikov static void 13459f7d47b0SAlexander V. Chernikov export_table_internal(struct namedobj_instance *ni, struct named_object *no, 13469f7d47b0SAlexander V. Chernikov void *arg) 13473b3a8eb9SGleb Smirnoff { 13489f7d47b0SAlexander V. Chernikov ipfw_xtable_info *i; 1349ac35ff17SAlexander V. Chernikov struct dump_table_args *dta; 13503b3a8eb9SGleb Smirnoff 1351ac35ff17SAlexander V. Chernikov dta = (struct dump_table_args *)arg; 1352ac35ff17SAlexander V. Chernikov 1353ac35ff17SAlexander V. Chernikov i = (ipfw_xtable_info *)ipfw_get_sopt_space(dta->sd, sizeof(*i)); 135468394ec8SAlexander V. Chernikov KASSERT(i != 0, ("previously checked buffer is not enough")); 13559f7d47b0SAlexander V. Chernikov 1356ac35ff17SAlexander V. Chernikov export_table_info(dta->ch, (struct table_config *)no, i); 13579f7d47b0SAlexander V. Chernikov } 13589f7d47b0SAlexander V. Chernikov 1359f1220db8SAlexander V. Chernikov /* 1360f1220db8SAlexander V. Chernikov * Export all tables as ipfw_xtable_info structures to 13612d99a349SAlexander V. Chernikov * storage provided by @sd. 1362f1220db8SAlexander V. Chernikov * Returns 0 on success. 1363f1220db8SAlexander V. Chernikov */ 1364f1220db8SAlexander V. Chernikov static int 13652d99a349SAlexander V. Chernikov export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, 13662d99a349SAlexander V. Chernikov struct sockopt_data *sd) 13679f7d47b0SAlexander V. Chernikov { 13689f7d47b0SAlexander V. Chernikov uint32_t size; 13699f7d47b0SAlexander V. Chernikov uint32_t count; 1370ac35ff17SAlexander V. Chernikov struct dump_table_args dta; 13719f7d47b0SAlexander V. Chernikov 13729f7d47b0SAlexander V. Chernikov count = ipfw_objhash_count(CHAIN_TO_NI(ch)); 13739f7d47b0SAlexander V. Chernikov size = count * sizeof(ipfw_xtable_info) + sizeof(ipfw_obj_lheader); 13742d99a349SAlexander V. Chernikov 13752d99a349SAlexander V. Chernikov /* Fill in header regadless of buffer size */ 1376f1220db8SAlexander V. Chernikov olh->count = count; 1377f1220db8SAlexander V. Chernikov olh->objsize = sizeof(ipfw_xtable_info); 13782d99a349SAlexander V. Chernikov 13792d99a349SAlexander V. Chernikov if (size > olh->size) { 13802d99a349SAlexander V. Chernikov olh->size = size; 13819f7d47b0SAlexander V. Chernikov return (ENOMEM); 1382f1220db8SAlexander V. Chernikov } 138368394ec8SAlexander V. Chernikov 13849f7d47b0SAlexander V. Chernikov olh->size = size; 13852d99a349SAlexander V. Chernikov 1386ac35ff17SAlexander V. Chernikov dta.ch = ch; 1387ac35ff17SAlexander V. Chernikov dta.sd = sd; 1388ac35ff17SAlexander V. Chernikov 1389ac35ff17SAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), export_table_internal, &dta); 13909f7d47b0SAlexander V. Chernikov 13913b3a8eb9SGleb Smirnoff return (0); 13923b3a8eb9SGleb Smirnoff } 13933b3a8eb9SGleb Smirnoff 139481d3153dSAlexander V. Chernikov /* 139581d3153dSAlexander V. Chernikov * Legacy IP_FW_TABLE_GETSIZE handler 139681d3153dSAlexander V. Chernikov */ 13973b3a8eb9SGleb Smirnoff int 1398b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 13993b3a8eb9SGleb Smirnoff { 1400b074b7bbSAlexander V. Chernikov struct table_config *tc; 14013b3a8eb9SGleb Smirnoff 1402b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1403b074b7bbSAlexander V. Chernikov return (ESRCH); 14049f7d47b0SAlexander V. Chernikov *cnt = tc->count; 14053b3a8eb9SGleb Smirnoff return (0); 14063b3a8eb9SGleb Smirnoff } 14073b3a8eb9SGleb Smirnoff 14089f7d47b0SAlexander V. Chernikov 140981d3153dSAlexander V. Chernikov /* 141081d3153dSAlexander V. Chernikov * Legacy IP_FW_TABLE_XGETSIZE handler 141181d3153dSAlexander V. Chernikov */ 14129f7d47b0SAlexander V. Chernikov int 14139f7d47b0SAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 14143b3a8eb9SGleb Smirnoff { 14159f7d47b0SAlexander V. Chernikov struct table_config *tc; 14169f7d47b0SAlexander V. Chernikov 1417d3a4f924SAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) { 1418d3a4f924SAlexander V. Chernikov *cnt = 0; 14199f7d47b0SAlexander V. Chernikov return (0); /* 'table all list' requires success */ 1420d3a4f924SAlexander V. Chernikov } 14219f7d47b0SAlexander V. Chernikov *cnt = tc->count * sizeof(ipfw_table_xentry); 14229f7d47b0SAlexander V. Chernikov if (tc->count > 0) 14239f7d47b0SAlexander V. Chernikov *cnt += sizeof(ipfw_xtable); 14249f7d47b0SAlexander V. Chernikov return (0); 14259f7d47b0SAlexander V. Chernikov } 14269f7d47b0SAlexander V. Chernikov 14279f7d47b0SAlexander V. Chernikov static int 14289f7d47b0SAlexander V. Chernikov dump_table_entry(void *e, void *arg) 14299f7d47b0SAlexander V. Chernikov { 14309f7d47b0SAlexander V. Chernikov struct dump_args *da; 14319f7d47b0SAlexander V. Chernikov struct table_config *tc; 14329f7d47b0SAlexander V. Chernikov struct table_algo *ta; 14333b3a8eb9SGleb Smirnoff ipfw_table_entry *ent; 143481d3153dSAlexander V. Chernikov int error; 14353b3a8eb9SGleb Smirnoff 14369f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 14379f7d47b0SAlexander V. Chernikov 14389f7d47b0SAlexander V. Chernikov tc = da->tc; 14399f7d47b0SAlexander V. Chernikov ta = tc->ta; 14409f7d47b0SAlexander V. Chernikov 14419f7d47b0SAlexander V. Chernikov /* Out of memory, returning */ 1442f1220db8SAlexander V. Chernikov if (da->cnt == da->size) 14433b3a8eb9SGleb Smirnoff return (1); 1444f1220db8SAlexander V. Chernikov ent = da->ent++; 1445f1220db8SAlexander V. Chernikov ent->tbl = da->uidx; 1446f1220db8SAlexander V. Chernikov da->cnt++; 14479f7d47b0SAlexander V. Chernikov 144881d3153dSAlexander V. Chernikov error = ta->dump_tentry(tc->astate, da->ti, e, &da->tent); 144981d3153dSAlexander V. Chernikov if (error != 0) 145081d3153dSAlexander V. Chernikov return (error); 145181d3153dSAlexander V. Chernikov 145281d3153dSAlexander V. Chernikov ent->addr = da->tent.k.addr.s_addr; 145381d3153dSAlexander V. Chernikov ent->masklen = da->tent.masklen; 145481d3153dSAlexander V. Chernikov ent->value = da->tent.value; 145581d3153dSAlexander V. Chernikov 145681d3153dSAlexander V. Chernikov return (0); 14573b3a8eb9SGleb Smirnoff } 14583b3a8eb9SGleb Smirnoff 1459f1220db8SAlexander V. Chernikov /* 1460f1220db8SAlexander V. Chernikov * Dumps table in pre-8.1 legacy format. 1461f1220db8SAlexander V. Chernikov */ 14623b3a8eb9SGleb Smirnoff int 1463f1220db8SAlexander V. Chernikov ipfw_dump_table_legacy(struct ip_fw_chain *ch, struct tid_info *ti, 1464f1220db8SAlexander V. Chernikov ipfw_table *tbl) 14653b3a8eb9SGleb Smirnoff { 1466b074b7bbSAlexander V. Chernikov struct table_config *tc; 14679f7d47b0SAlexander V. Chernikov struct table_algo *ta; 14689f7d47b0SAlexander V. Chernikov struct dump_args da; 14693b3a8eb9SGleb Smirnoff 14703b3a8eb9SGleb Smirnoff tbl->cnt = 0; 14713b3a8eb9SGleb Smirnoff 1472b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 1473b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 14749f7d47b0SAlexander V. Chernikov 14759f7d47b0SAlexander V. Chernikov ta = tc->ta; 14769f7d47b0SAlexander V. Chernikov 147781d3153dSAlexander V. Chernikov /* This dump format supports IPv4 only */ 147881d3153dSAlexander V. Chernikov if (tc->no.type != IPFW_TABLE_CIDR) 147981d3153dSAlexander V. Chernikov return (0); 14809f7d47b0SAlexander V. Chernikov 1481d3a4f924SAlexander V. Chernikov memset(&da, 0, sizeof(da)); 14829f7d47b0SAlexander V. Chernikov da.ti = KIDX_TO_TI(ch, tc->no.kidx); 14839f7d47b0SAlexander V. Chernikov da.tc = tc; 1484f1220db8SAlexander V. Chernikov da.ent = &tbl->ent[0]; 1485f1220db8SAlexander V. Chernikov da.size = tbl->size; 14869f7d47b0SAlexander V. Chernikov 14879f7d47b0SAlexander V. Chernikov tbl->cnt = 0; 14889f7d47b0SAlexander V. Chernikov ta->foreach(tc->astate, da.ti, dump_table_entry, &da); 1489f1220db8SAlexander V. Chernikov tbl->cnt = da.cnt; 14909f7d47b0SAlexander V. Chernikov 14913b3a8eb9SGleb Smirnoff return (0); 14923b3a8eb9SGleb Smirnoff } 14933b3a8eb9SGleb Smirnoff 14949490a627SAlexander V. Chernikov /* 149581d3153dSAlexander V. Chernikov * Dumps table entry in eXtended format (v1)(current). 149681d3153dSAlexander V. Chernikov */ 149781d3153dSAlexander V. Chernikov static int 149881d3153dSAlexander V. Chernikov dump_table_tentry(void *e, void *arg) 149981d3153dSAlexander V. Chernikov { 150081d3153dSAlexander V. Chernikov struct dump_args *da; 150181d3153dSAlexander V. Chernikov struct table_config *tc; 150281d3153dSAlexander V. Chernikov struct table_algo *ta; 150381d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 150481d3153dSAlexander V. Chernikov 150581d3153dSAlexander V. Chernikov da = (struct dump_args *)arg; 150681d3153dSAlexander V. Chernikov 150781d3153dSAlexander V. Chernikov tc = da->tc; 150881d3153dSAlexander V. Chernikov ta = tc->ta; 150981d3153dSAlexander V. Chernikov 151081d3153dSAlexander V. Chernikov tent = (ipfw_obj_tentry *)ipfw_get_sopt_space(da->sd, sizeof(*tent)); 151181d3153dSAlexander V. Chernikov /* Out of memory, returning */ 151281d3153dSAlexander V. Chernikov if (tent == NULL) { 151381d3153dSAlexander V. Chernikov da->error = ENOMEM; 151481d3153dSAlexander V. Chernikov return (1); 151581d3153dSAlexander V. Chernikov } 151681d3153dSAlexander V. Chernikov tent->head.length = sizeof(ipfw_obj_tentry); 151781d3153dSAlexander V. Chernikov tent->idx = da->uidx; 151881d3153dSAlexander V. Chernikov 151981d3153dSAlexander V. Chernikov return (ta->dump_tentry(tc->astate, da->ti, e, tent)); 152081d3153dSAlexander V. Chernikov } 152181d3153dSAlexander V. Chernikov 152281d3153dSAlexander V. Chernikov /* 152381d3153dSAlexander V. Chernikov * Dumps table entry in eXtended format (v0). 15249490a627SAlexander V. Chernikov */ 15253b3a8eb9SGleb Smirnoff static int 15269f7d47b0SAlexander V. Chernikov dump_table_xentry(void *e, void *arg) 15273b3a8eb9SGleb Smirnoff { 15289f7d47b0SAlexander V. Chernikov struct dump_args *da; 15299f7d47b0SAlexander V. Chernikov struct table_config *tc; 15309f7d47b0SAlexander V. Chernikov struct table_algo *ta; 15313b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 153281d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent; 153381d3153dSAlexander V. Chernikov int error; 15343b3a8eb9SGleb Smirnoff 15359f7d47b0SAlexander V. Chernikov da = (struct dump_args *)arg; 15369f7d47b0SAlexander V. Chernikov 15379f7d47b0SAlexander V. Chernikov tc = da->tc; 15389f7d47b0SAlexander V. Chernikov ta = tc->ta; 15399f7d47b0SAlexander V. Chernikov 15402d99a349SAlexander V. Chernikov xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent)); 15413b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 15422d99a349SAlexander V. Chernikov if (xent == NULL) 15433b3a8eb9SGleb Smirnoff return (1); 15443b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 1545f1220db8SAlexander V. Chernikov xent->tbl = da->uidx; 15469f7d47b0SAlexander V. Chernikov 154781d3153dSAlexander V. Chernikov memset(&da->tent, 0, sizeof(da->tent)); 154881d3153dSAlexander V. Chernikov tent = &da->tent; 154981d3153dSAlexander V. Chernikov error = ta->dump_tentry(tc->astate, da->ti, e, tent); 155081d3153dSAlexander V. Chernikov if (error != 0) 155181d3153dSAlexander V. Chernikov return (error); 155281d3153dSAlexander V. Chernikov 155381d3153dSAlexander V. Chernikov /* Convert current format to previous one */ 155481d3153dSAlexander V. Chernikov xent->masklen = tent->masklen; 155581d3153dSAlexander V. Chernikov xent->value = tent->value; 155681d3153dSAlexander V. Chernikov /* Apply some hacks */ 155781d3153dSAlexander V. Chernikov if (tc->no.type == IPFW_TABLE_CIDR && tent->subtype == AF_INET) { 155881d3153dSAlexander V. Chernikov xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr; 155981d3153dSAlexander V. Chernikov xent->flags = IPFW_TCF_INET; 156081d3153dSAlexander V. Chernikov } else 156181d3153dSAlexander V. Chernikov memcpy(&xent->k, &tent->k, sizeof(xent->k)); 156281d3153dSAlexander V. Chernikov 156381d3153dSAlexander V. Chernikov return (0); 15649f7d47b0SAlexander V. Chernikov } 15659f7d47b0SAlexander V. Chernikov 15669f7d47b0SAlexander V. Chernikov /* 15679f7d47b0SAlexander V. Chernikov * Table algorithms 15689f7d47b0SAlexander V. Chernikov */ 15693b3a8eb9SGleb Smirnoff 15709f7d47b0SAlexander V. Chernikov /* 15719490a627SAlexander V. Chernikov * Finds algoritm by index, table type or supplied name 15729f7d47b0SAlexander V. Chernikov */ 15739f7d47b0SAlexander V. Chernikov static struct table_algo * 15749490a627SAlexander V. Chernikov find_table_algo(struct tables_config *tcfg, struct tid_info *ti, char *name) 15759f7d47b0SAlexander V. Chernikov { 15769490a627SAlexander V. Chernikov int i, l; 15779490a627SAlexander V. Chernikov struct table_algo *ta; 15789f7d47b0SAlexander V. Chernikov 157957a1cf95SAlexander V. Chernikov if (ti->type > IPFW_TABLE_MAXTYPE) 158057a1cf95SAlexander V. Chernikov return (NULL); 158157a1cf95SAlexander V. Chernikov 15829f7d47b0SAlexander V. Chernikov /* Search by index */ 15839f7d47b0SAlexander V. Chernikov if (ti->atype != 0) { 15849f7d47b0SAlexander V. Chernikov if (ti->atype > tcfg->algo_count) 15859f7d47b0SAlexander V. Chernikov return (NULL); 15869f7d47b0SAlexander V. Chernikov return (tcfg->algo[ti->atype]); 15879f7d47b0SAlexander V. Chernikov } 15889f7d47b0SAlexander V. Chernikov 15899490a627SAlexander V. Chernikov /* Search by name if supplied */ 15909490a627SAlexander V. Chernikov if (name != NULL) { 15919490a627SAlexander V. Chernikov /* TODO: better search */ 15929490a627SAlexander V. Chernikov for (i = 1; i <= tcfg->algo_count; i++) { 15939490a627SAlexander V. Chernikov ta = tcfg->algo[i]; 15949490a627SAlexander V. Chernikov 15959490a627SAlexander V. Chernikov /* 15969490a627SAlexander V. Chernikov * One can supply additional algorithm 15979490a627SAlexander V. Chernikov * parameters so we compare only the first word 15989490a627SAlexander V. Chernikov * of supplied name: 15999490a627SAlexander V. Chernikov * 'hash_cidr hsize=32' 16009490a627SAlexander V. Chernikov * '^^^^^^^^^' 16019490a627SAlexander V. Chernikov * 16029490a627SAlexander V. Chernikov */ 16039490a627SAlexander V. Chernikov l = strlen(ta->name); 16049490a627SAlexander V. Chernikov if (strncmp(name, ta->name, l) == 0) { 16059490a627SAlexander V. Chernikov if (name[l] == '\0' || name[l] == ' ') 16069490a627SAlexander V. Chernikov return (ta); 16079490a627SAlexander V. Chernikov } 16089490a627SAlexander V. Chernikov } 16099490a627SAlexander V. Chernikov 16109490a627SAlexander V. Chernikov return (NULL); 16119490a627SAlexander V. Chernikov } 16129490a627SAlexander V. Chernikov 161357a1cf95SAlexander V. Chernikov /* Return default algorithm for given type if set */ 161457a1cf95SAlexander V. Chernikov return (tcfg->def_algo[ti->type]); 16153b3a8eb9SGleb Smirnoff } 16163b3a8eb9SGleb Smirnoff 16170b565ac0SAlexander V. Chernikov int 16180b565ac0SAlexander V. Chernikov ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta, size_t size, 16190b565ac0SAlexander V. Chernikov int *idx) 16203b3a8eb9SGleb Smirnoff { 16219f7d47b0SAlexander V. Chernikov struct tables_config *tcfg; 16220b565ac0SAlexander V. Chernikov struct table_algo *ta_new; 16230b565ac0SAlexander V. Chernikov 16240b565ac0SAlexander V. Chernikov if (size > sizeof(struct table_algo)) 16250b565ac0SAlexander V. Chernikov return (EINVAL); 16260b565ac0SAlexander V. Chernikov 162757a1cf95SAlexander V. Chernikov KASSERT(ta->type >= IPFW_TABLE_MAXTYPE,("Increase IPFW_TABLE_MAXTYPE")); 162857a1cf95SAlexander V. Chernikov 16290b565ac0SAlexander V. Chernikov ta_new = malloc(sizeof(struct table_algo), M_IPFW, M_WAITOK | M_ZERO); 16300b565ac0SAlexander V. Chernikov memcpy(ta_new, ta, size); 16313b3a8eb9SGleb Smirnoff 16329f7d47b0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 1633b074b7bbSAlexander V. Chernikov 16349f7d47b0SAlexander V. Chernikov KASSERT(tcfg->algo_count < 255, ("Increase algo array size")); 16359f7d47b0SAlexander V. Chernikov 16360b565ac0SAlexander V. Chernikov tcfg->algo[++tcfg->algo_count] = ta_new; 16370b565ac0SAlexander V. Chernikov ta_new->idx = tcfg->algo_count; 16380b565ac0SAlexander V. Chernikov 163957a1cf95SAlexander V. Chernikov /* Set algorithm as default one for given type */ 164057a1cf95SAlexander V. Chernikov if ((ta_new->flags & TA_FLAG_DEFAULT) != 0 && 164157a1cf95SAlexander V. Chernikov tcfg->def_algo[ta_new->type] == NULL) 164257a1cf95SAlexander V. Chernikov tcfg->def_algo[ta_new->type] = ta_new; 164357a1cf95SAlexander V. Chernikov 16440b565ac0SAlexander V. Chernikov *idx = ta_new->idx; 16450b565ac0SAlexander V. Chernikov 16460b565ac0SAlexander V. Chernikov return (0); 16470b565ac0SAlexander V. Chernikov } 16480b565ac0SAlexander V. Chernikov 16490b565ac0SAlexander V. Chernikov void 16500b565ac0SAlexander V. Chernikov ipfw_del_table_algo(struct ip_fw_chain *ch, int idx) 16510b565ac0SAlexander V. Chernikov { 16520b565ac0SAlexander V. Chernikov struct tables_config *tcfg; 16530b565ac0SAlexander V. Chernikov struct table_algo *ta; 16540b565ac0SAlexander V. Chernikov 16550b565ac0SAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 16560b565ac0SAlexander V. Chernikov 16570b565ac0SAlexander V. Chernikov KASSERT(idx <= tcfg->algo_count, ("algo idx %d out of rage 1..%d", idx, 16580b565ac0SAlexander V. Chernikov tcfg->algo_count)); 16590b565ac0SAlexander V. Chernikov 16600b565ac0SAlexander V. Chernikov ta = tcfg->algo[idx]; 16610b565ac0SAlexander V. Chernikov KASSERT(ta != NULL, ("algo idx %d is NULL", idx)); 166257a1cf95SAlexander V. Chernikov 166357a1cf95SAlexander V. Chernikov if (tcfg->def_algo[ta->type] == ta) 166457a1cf95SAlexander V. Chernikov tcfg->def_algo[ta->type] = NULL; 166557a1cf95SAlexander V. Chernikov 16660b565ac0SAlexander V. Chernikov free(ta, M_IPFW); 16673b3a8eb9SGleb Smirnoff } 16683b3a8eb9SGleb Smirnoff 16699d099b4fSAlexander V. Chernikov /* 16709d099b4fSAlexander V. Chernikov * Lists all table algorithms currently available. 16719d099b4fSAlexander V. Chernikov * Data layout (v0)(current): 16729d099b4fSAlexander V. Chernikov * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 16739d099b4fSAlexander V. Chernikov * Reply: [ ipfw_obj_lheader ipfw_ta_info x N ] 16749d099b4fSAlexander V. Chernikov * 16759d099b4fSAlexander V. Chernikov * Returns 0 on success 16769d099b4fSAlexander V. Chernikov */ 16779d099b4fSAlexander V. Chernikov int 16789d099b4fSAlexander V. Chernikov ipfw_list_table_algo(struct ip_fw_chain *ch, struct sockopt_data *sd) 16799d099b4fSAlexander V. Chernikov { 16809d099b4fSAlexander V. Chernikov struct _ipfw_obj_lheader *olh; 16819d099b4fSAlexander V. Chernikov struct tables_config *tcfg; 16829d099b4fSAlexander V. Chernikov ipfw_ta_info *i; 16839d099b4fSAlexander V. Chernikov struct table_algo *ta; 16849d099b4fSAlexander V. Chernikov uint32_t count, n, size; 16859d099b4fSAlexander V. Chernikov 16869d099b4fSAlexander V. Chernikov olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 16879d099b4fSAlexander V. Chernikov if (olh == NULL) 16889d099b4fSAlexander V. Chernikov return (EINVAL); 16899d099b4fSAlexander V. Chernikov if (sd->valsize < olh->size) 16909d099b4fSAlexander V. Chernikov return (EINVAL); 16919d099b4fSAlexander V. Chernikov 16929d099b4fSAlexander V. Chernikov IPFW_UH_RLOCK(ch); 16939d099b4fSAlexander V. Chernikov tcfg = CHAIN_TO_TCFG(ch); 16949d099b4fSAlexander V. Chernikov count = tcfg->algo_count; 16959d099b4fSAlexander V. Chernikov size = count * sizeof(ipfw_ta_info) + sizeof(ipfw_obj_lheader); 16969d099b4fSAlexander V. Chernikov 16979d099b4fSAlexander V. Chernikov /* Fill in header regadless of buffer size */ 16989d099b4fSAlexander V. Chernikov olh->count = count; 16999d099b4fSAlexander V. Chernikov olh->objsize = sizeof(ipfw_ta_info); 17009d099b4fSAlexander V. Chernikov 17019d099b4fSAlexander V. Chernikov if (size > olh->size) { 17029d099b4fSAlexander V. Chernikov olh->size = size; 17039d099b4fSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 17049d099b4fSAlexander V. Chernikov return (ENOMEM); 17059d099b4fSAlexander V. Chernikov } 17069d099b4fSAlexander V. Chernikov olh->size = size; 17079d099b4fSAlexander V. Chernikov 17089d099b4fSAlexander V. Chernikov for (n = 1; n <= count; n++) { 17099d099b4fSAlexander V. Chernikov i = (ipfw_ta_info *)ipfw_get_sopt_space(sd, sizeof(*i)); 17109d099b4fSAlexander V. Chernikov KASSERT(i != 0, ("previously checked buffer is not enough")); 17119d099b4fSAlexander V. Chernikov ta = tcfg->algo[n]; 17129d099b4fSAlexander V. Chernikov strlcpy(i->algoname, ta->name, sizeof(i->algoname)); 17139d099b4fSAlexander V. Chernikov i->type = ta->type; 17149d099b4fSAlexander V. Chernikov i->refcnt = ta->refcnt; 17159d099b4fSAlexander V. Chernikov } 17169d099b4fSAlexander V. Chernikov 17179d099b4fSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 17189d099b4fSAlexander V. Chernikov 17199d099b4fSAlexander V. Chernikov return (0); 17209d099b4fSAlexander V. Chernikov } 17219d099b4fSAlexander V. Chernikov 17229f7d47b0SAlexander V. Chernikov 1723b074b7bbSAlexander V. Chernikov /* 1724b074b7bbSAlexander V. Chernikov * Tables rewriting code 1725b074b7bbSAlexander V. Chernikov * 1726b074b7bbSAlexander V. Chernikov */ 1727b074b7bbSAlexander V. Chernikov 1728b074b7bbSAlexander V. Chernikov /* 1729b074b7bbSAlexander V. Chernikov * Determine table number and lookup type for @cmd. 1730b074b7bbSAlexander V. Chernikov * Fill @tbl and @type with appropriate values. 1731b074b7bbSAlexander V. Chernikov * Returns 0 for relevant opcodes, 1 otherwise. 1732b074b7bbSAlexander V. Chernikov */ 1733b074b7bbSAlexander V. Chernikov static int 1734b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 1735b074b7bbSAlexander V. Chernikov { 1736b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1737b074b7bbSAlexander V. Chernikov int skip; 1738b074b7bbSAlexander V. Chernikov uint16_t v; 1739b074b7bbSAlexander V. Chernikov 1740b074b7bbSAlexander V. Chernikov skip = 1; 1741b074b7bbSAlexander V. Chernikov 1742b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1743b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1744b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1745b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1746b074b7bbSAlexander V. Chernikov *puidx = cmd->arg1; 1747b074b7bbSAlexander V. Chernikov /* Assume CIDR by default */ 1748b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 1749b074b7bbSAlexander V. Chernikov skip = 0; 1750b074b7bbSAlexander V. Chernikov 1751b074b7bbSAlexander V. Chernikov if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { 1752b074b7bbSAlexander V. Chernikov /* 1753b074b7bbSAlexander V. Chernikov * generic lookup. The key must be 1754b074b7bbSAlexander V. Chernikov * in 32bit big-endian format. 1755b074b7bbSAlexander V. Chernikov */ 1756b074b7bbSAlexander V. Chernikov v = ((ipfw_insn_u32 *)cmd)->d[1]; 1757b074b7bbSAlexander V. Chernikov switch (v) { 1758b074b7bbSAlexander V. Chernikov case 0: 1759b074b7bbSAlexander V. Chernikov case 1: 1760b074b7bbSAlexander V. Chernikov /* IPv4 src/dst */ 1761b074b7bbSAlexander V. Chernikov break; 1762b074b7bbSAlexander V. Chernikov case 2: 1763b074b7bbSAlexander V. Chernikov case 3: 1764b074b7bbSAlexander V. Chernikov /* src/dst port */ 1765b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1766b074b7bbSAlexander V. Chernikov break; 1767b074b7bbSAlexander V. Chernikov case 4: 1768b074b7bbSAlexander V. Chernikov /* uid/gid */ 1769b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1770b23d5de9SAlexander V. Chernikov break; 1771b074b7bbSAlexander V. Chernikov case 5: 1772b074b7bbSAlexander V. Chernikov /* jid */ 1773b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1774b23d5de9SAlexander V. Chernikov break; 1775b074b7bbSAlexander V. Chernikov case 6: 1776b074b7bbSAlexander V. Chernikov /* dscp */ 1777b23d5de9SAlexander V. Chernikov *ptype = IPFW_TABLE_NUMBER; 1778b074b7bbSAlexander V. Chernikov break; 1779b074b7bbSAlexander V. Chernikov } 1780b074b7bbSAlexander V. Chernikov } 1781b074b7bbSAlexander V. Chernikov break; 1782b074b7bbSAlexander V. Chernikov case O_XMIT: 1783b074b7bbSAlexander V. Chernikov case O_RECV: 1784b074b7bbSAlexander V. Chernikov case O_VIA: 1785b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1786b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1787b074b7bbSAlexander V. Chernikov if (cmdif->name[0] != '\1') 1788b074b7bbSAlexander V. Chernikov break; 1789b074b7bbSAlexander V. Chernikov 1790b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 1791b074b7bbSAlexander V. Chernikov *puidx = cmdif->p.glob; 1792b074b7bbSAlexander V. Chernikov skip = 0; 1793b074b7bbSAlexander V. Chernikov break; 1794914bffb6SAlexander V. Chernikov case O_IP_FLOW_LOOKUP: 1795914bffb6SAlexander V. Chernikov *puidx = cmd->arg1; 1796914bffb6SAlexander V. Chernikov *ptype = IPFW_TABLE_FLOW; 1797914bffb6SAlexander V. Chernikov skip = 0; 1798914bffb6SAlexander V. Chernikov break; 1799b074b7bbSAlexander V. Chernikov } 1800b074b7bbSAlexander V. Chernikov 1801b074b7bbSAlexander V. Chernikov return (skip); 1802b074b7bbSAlexander V. Chernikov } 1803b074b7bbSAlexander V. Chernikov 1804b074b7bbSAlexander V. Chernikov /* 1805b074b7bbSAlexander V. Chernikov * Sets new table value for given opcode. 1806b074b7bbSAlexander V. Chernikov * Assume the same opcodes as classify_table_opcode() 1807b074b7bbSAlexander V. Chernikov */ 1808b074b7bbSAlexander V. Chernikov static void 1809b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx) 1810b074b7bbSAlexander V. Chernikov { 1811b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1812b074b7bbSAlexander V. Chernikov 1813b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1814b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1815b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1816b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1817b074b7bbSAlexander V. Chernikov cmd->arg1 = idx; 1818b074b7bbSAlexander V. Chernikov break; 1819b074b7bbSAlexander V. Chernikov case O_XMIT: 1820b074b7bbSAlexander V. Chernikov case O_RECV: 1821b074b7bbSAlexander V. Chernikov case O_VIA: 1822b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1823b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1824b074b7bbSAlexander V. Chernikov cmdif->p.glob = idx; 1825b074b7bbSAlexander V. Chernikov break; 1826914bffb6SAlexander V. Chernikov case O_IP_FLOW_LOOKUP: 1827914bffb6SAlexander V. Chernikov cmd->arg1 = idx; 1828914bffb6SAlexander V. Chernikov break; 1829b074b7bbSAlexander V. Chernikov } 1830b074b7bbSAlexander V. Chernikov } 1831b074b7bbSAlexander V. Chernikov 1832ac35ff17SAlexander V. Chernikov /* 1833ac35ff17SAlexander V. Chernikov * Checks table name for validity. 1834ac35ff17SAlexander V. Chernikov * Enforce basic length checks, the rest 1835ac35ff17SAlexander V. Chernikov * should be done in userland. 1836ac35ff17SAlexander V. Chernikov * 1837ac35ff17SAlexander V. Chernikov * Returns 0 if name is considered valid. 1838ac35ff17SAlexander V. Chernikov */ 1839ac35ff17SAlexander V. Chernikov int 1840ac35ff17SAlexander V. Chernikov ipfw_check_table_name(char *name) 1841ac35ff17SAlexander V. Chernikov { 1842ac35ff17SAlexander V. Chernikov int nsize; 1843ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv = NULL; 1844ac35ff17SAlexander V. Chernikov 1845ac35ff17SAlexander V. Chernikov nsize = sizeof(ntlv->name); 1846ac35ff17SAlexander V. Chernikov 1847ac35ff17SAlexander V. Chernikov if (strnlen(name, nsize) == nsize) 1848ac35ff17SAlexander V. Chernikov return (EINVAL); 1849ac35ff17SAlexander V. Chernikov 1850ac35ff17SAlexander V. Chernikov if (name[0] == '\0') 1851ac35ff17SAlexander V. Chernikov return (EINVAL); 1852ac35ff17SAlexander V. Chernikov 1853ac35ff17SAlexander V. Chernikov /* 1854ac35ff17SAlexander V. Chernikov * TODO: do some more complicated checks 1855ac35ff17SAlexander V. Chernikov */ 1856ac35ff17SAlexander V. Chernikov 1857ac35ff17SAlexander V. Chernikov return (0); 1858ac35ff17SAlexander V. Chernikov } 1859ac35ff17SAlexander V. Chernikov 1860ac35ff17SAlexander V. Chernikov /* 1861ac35ff17SAlexander V. Chernikov * Find tablename TLV by @uid. 1862ac35ff17SAlexander V. Chernikov * Check @tlvs for valid data inside. 1863ac35ff17SAlexander V. Chernikov * 1864ac35ff17SAlexander V. Chernikov * Returns pointer to found TLV or NULL. 1865ac35ff17SAlexander V. Chernikov */ 1866ac35ff17SAlexander V. Chernikov static ipfw_obj_ntlv * 1867b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx) 1868b074b7bbSAlexander V. Chernikov { 18699f7d47b0SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1870b074b7bbSAlexander V. Chernikov uintptr_t pa, pe; 1871b074b7bbSAlexander V. Chernikov int l; 1872b074b7bbSAlexander V. Chernikov 1873b074b7bbSAlexander V. Chernikov pa = (uintptr_t)tlvs; 1874b074b7bbSAlexander V. Chernikov pe = pa + len; 1875b074b7bbSAlexander V. Chernikov l = 0; 1876b074b7bbSAlexander V. Chernikov for (; pa < pe; pa += l) { 18779f7d47b0SAlexander V. Chernikov ntlv = (ipfw_obj_ntlv *)pa; 1878b074b7bbSAlexander V. Chernikov l = ntlv->head.length; 1879ac35ff17SAlexander V. Chernikov 1880ac35ff17SAlexander V. Chernikov if (l != sizeof(*ntlv)) 1881ac35ff17SAlexander V. Chernikov return (NULL); 1882ac35ff17SAlexander V. Chernikov 1883563b5ab1SAlexander V. Chernikov if (ntlv->head.type != IPFW_TLV_TBL_NAME) 1884b074b7bbSAlexander V. Chernikov continue; 1885ac35ff17SAlexander V. Chernikov 1886b074b7bbSAlexander V. Chernikov if (ntlv->idx != uidx) 1887b074b7bbSAlexander V. Chernikov continue; 1888b074b7bbSAlexander V. Chernikov 1889ac35ff17SAlexander V. Chernikov if (ipfw_check_table_name(ntlv->name) != 0) 1890ac35ff17SAlexander V. Chernikov return (NULL); 1891ac35ff17SAlexander V. Chernikov 1892ac35ff17SAlexander V. Chernikov return (ntlv); 1893b074b7bbSAlexander V. Chernikov } 1894b074b7bbSAlexander V. Chernikov 1895b074b7bbSAlexander V. Chernikov return (NULL); 1896b074b7bbSAlexander V. Chernikov } 1897b074b7bbSAlexander V. Chernikov 1898ac35ff17SAlexander V. Chernikov /* 1899ac35ff17SAlexander V. Chernikov * Finds table config based on either legacy index 1900ac35ff17SAlexander V. Chernikov * or name in ntlv. 1901ac35ff17SAlexander V. Chernikov * Note @ti structure contains unchecked data from userland. 1902ac35ff17SAlexander V. Chernikov * 1903ac35ff17SAlexander V. Chernikov * Returns pointer to table_config or NULL. 1904ac35ff17SAlexander V. Chernikov */ 1905b074b7bbSAlexander V. Chernikov static struct table_config * 1906b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti) 1907b074b7bbSAlexander V. Chernikov { 1908b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1909b074b7bbSAlexander V. Chernikov struct named_object *no; 1910ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1911ac35ff17SAlexander V. Chernikov uint32_t set; 1912b074b7bbSAlexander V. Chernikov 1913b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1914ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1915ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1916b074b7bbSAlexander V. Chernikov return (NULL); 1917ac35ff17SAlexander V. Chernikov name = ntlv->name; 1918ac35ff17SAlexander V. Chernikov set = ntlv->set; 1919b074b7bbSAlexander V. Chernikov } else { 1920b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1921b074b7bbSAlexander V. Chernikov name = bname; 1922ac35ff17SAlexander V. Chernikov set = 0; 1923b074b7bbSAlexander V. Chernikov } 1924b074b7bbSAlexander V. Chernikov 1925ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_name(ni, set, name); 1926b074b7bbSAlexander V. Chernikov 1927b074b7bbSAlexander V. Chernikov return ((struct table_config *)no); 1928b074b7bbSAlexander V. Chernikov } 1929b074b7bbSAlexander V. Chernikov 1930b074b7bbSAlexander V. Chernikov static struct table_config * 193168394ec8SAlexander V. Chernikov alloc_table_config(struct ip_fw_chain *ch, struct tid_info *ti, 1932914bffb6SAlexander V. Chernikov struct table_algo *ta, char *aname, uint8_t tflags, uint8_t vtype) 1933b074b7bbSAlexander V. Chernikov { 1934b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1935b074b7bbSAlexander V. Chernikov struct table_config *tc; 1936b074b7bbSAlexander V. Chernikov int error; 1937ac35ff17SAlexander V. Chernikov ipfw_obj_ntlv *ntlv; 1938ac35ff17SAlexander V. Chernikov uint32_t set; 1939b074b7bbSAlexander V. Chernikov 1940b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1941ac35ff17SAlexander V. Chernikov ntlv = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1942ac35ff17SAlexander V. Chernikov if (ntlv == NULL) 1943b074b7bbSAlexander V. Chernikov return (NULL); 1944ac35ff17SAlexander V. Chernikov name = ntlv->name; 1945ac35ff17SAlexander V. Chernikov set = ntlv->set; 1946b074b7bbSAlexander V. Chernikov } else { 1947b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1948b074b7bbSAlexander V. Chernikov name = bname; 1949ac35ff17SAlexander V. Chernikov set = 0; 1950b074b7bbSAlexander V. Chernikov } 1951b074b7bbSAlexander V. Chernikov 1952b074b7bbSAlexander V. Chernikov tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO); 1953b074b7bbSAlexander V. Chernikov tc->no.name = tc->tablename; 1954b074b7bbSAlexander V. Chernikov tc->no.type = ti->type; 1955ac35ff17SAlexander V. Chernikov tc->no.set = set; 1956914bffb6SAlexander V. Chernikov tc->tflags = tflags; 19579f7d47b0SAlexander V. Chernikov tc->ta = ta; 1958b074b7bbSAlexander V. Chernikov strlcpy(tc->tablename, name, sizeof(tc->tablename)); 1959ac35ff17SAlexander V. Chernikov /* Set default value type to u32 for compability reasons */ 1960db785d31SAlexander V. Chernikov if (vtype == 0) 1961ac35ff17SAlexander V. Chernikov tc->vtype = IPFW_VTYPE_U32; 1962db785d31SAlexander V. Chernikov else 1963db785d31SAlexander V. Chernikov tc->vtype = vtype; 1964b074b7bbSAlexander V. Chernikov 1965b074b7bbSAlexander V. Chernikov if (ti->tlvs == NULL) { 1966b074b7bbSAlexander V. Chernikov tc->no.compat = 1; 1967b074b7bbSAlexander V. Chernikov tc->no.uidx = ti->uidx; 1968b074b7bbSAlexander V. Chernikov } 1969b074b7bbSAlexander V. Chernikov 1970b074b7bbSAlexander V. Chernikov /* Preallocate data structures for new tables */ 1971914bffb6SAlexander V. Chernikov error = ta->init(ch, &tc->astate, &tc->ti, aname, tflags); 1972b074b7bbSAlexander V. Chernikov if (error != 0) { 1973b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1974b074b7bbSAlexander V. Chernikov return (NULL); 1975b074b7bbSAlexander V. Chernikov } 1976b074b7bbSAlexander V. Chernikov 1977b074b7bbSAlexander V. Chernikov return (tc); 1978b074b7bbSAlexander V. Chernikov } 1979b074b7bbSAlexander V. Chernikov 1980b074b7bbSAlexander V. Chernikov static void 1981b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc) 1982b074b7bbSAlexander V. Chernikov { 1983b074b7bbSAlexander V. Chernikov 1984b074b7bbSAlexander V. Chernikov if (tc->linked == 0) 198568394ec8SAlexander V. Chernikov tc->ta->destroy(tc->astate, &tc->ti); 1986b074b7bbSAlexander V. Chernikov 1987b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1988b074b7bbSAlexander V. Chernikov } 1989b074b7bbSAlexander V. Chernikov 1990b074b7bbSAlexander V. Chernikov /* 1991b074b7bbSAlexander V. Chernikov * Links @tc to @chain table named instance. 1992b074b7bbSAlexander V. Chernikov * Sets appropriate type/states in @chain table info. 1993b074b7bbSAlexander V. Chernikov */ 1994b074b7bbSAlexander V. Chernikov static void 19959f7d47b0SAlexander V. Chernikov link_table(struct ip_fw_chain *ch, struct table_config *tc) 1996b074b7bbSAlexander V. Chernikov { 1997b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 19989f7d47b0SAlexander V. Chernikov struct table_info *ti; 1999b074b7bbSAlexander V. Chernikov uint16_t kidx; 2000b074b7bbSAlexander V. Chernikov 20019f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 20029f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 2003b074b7bbSAlexander V. Chernikov 20049f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 2005b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 2006b074b7bbSAlexander V. Chernikov 2007b074b7bbSAlexander V. Chernikov ipfw_objhash_add(ni, &tc->no); 20089f7d47b0SAlexander V. Chernikov 20099f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 20109f7d47b0SAlexander V. Chernikov *ti = tc->ti; 2011b074b7bbSAlexander V. Chernikov 201268394ec8SAlexander V. Chernikov /* Notify algo on real @ti address */ 201368394ec8SAlexander V. Chernikov if (tc->ta->change_ti != NULL) 201468394ec8SAlexander V. Chernikov tc->ta->change_ti(tc->astate, ti); 201568394ec8SAlexander V. Chernikov 2016b074b7bbSAlexander V. Chernikov tc->linked = 1; 20179d099b4fSAlexander V. Chernikov tc->ta->refcnt++; 2018b074b7bbSAlexander V. Chernikov } 2019b074b7bbSAlexander V. Chernikov 2020b074b7bbSAlexander V. Chernikov /* 2021b074b7bbSAlexander V. Chernikov * Unlinks @tc from @chain table named instance. 2022b074b7bbSAlexander V. Chernikov * Zeroes states in @chain and stores them in @tc. 2023b074b7bbSAlexander V. Chernikov */ 2024b074b7bbSAlexander V. Chernikov static void 20259f7d47b0SAlexander V. Chernikov unlink_table(struct ip_fw_chain *ch, struct table_config *tc) 2026b074b7bbSAlexander V. Chernikov { 2027b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 20289f7d47b0SAlexander V. Chernikov struct table_info *ti; 2029b074b7bbSAlexander V. Chernikov uint16_t kidx; 2030b074b7bbSAlexander V. Chernikov 20319f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(ch); 20329f7d47b0SAlexander V. Chernikov IPFW_WLOCK_ASSERT(ch); 2033b074b7bbSAlexander V. Chernikov 20349f7d47b0SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 2035b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 2036b074b7bbSAlexander V. Chernikov 20379f7d47b0SAlexander V. Chernikov /* Clear state. @ti copy is already saved inside @tc */ 2038b074b7bbSAlexander V. Chernikov ipfw_objhash_del(ni, &tc->no); 20399f7d47b0SAlexander V. Chernikov ti = KIDX_TO_TI(ch, kidx); 20409f7d47b0SAlexander V. Chernikov memset(ti, 0, sizeof(struct table_info)); 2041b074b7bbSAlexander V. Chernikov tc->linked = 0; 20429d099b4fSAlexander V. Chernikov tc->ta->refcnt--; 204368394ec8SAlexander V. Chernikov 204468394ec8SAlexander V. Chernikov /* Notify algo on real @ti address */ 204568394ec8SAlexander V. Chernikov if (tc->ta->change_ti != NULL) 204668394ec8SAlexander V. Chernikov tc->ta->change_ti(tc->astate, NULL); 2047b074b7bbSAlexander V. Chernikov } 2048b074b7bbSAlexander V. Chernikov 2049b074b7bbSAlexander V. Chernikov /* 2050b074b7bbSAlexander V. Chernikov * Finds named object by @uidx number. 2051b074b7bbSAlexander V. Chernikov * Refs found object, allocate new index for non-existing object. 20529490a627SAlexander V. Chernikov * Fills in @oib with userland/kernel indexes. 20539490a627SAlexander V. Chernikov * First free oidx pointer is saved back in @oib. 2054b074b7bbSAlexander V. Chernikov * 2055b074b7bbSAlexander V. Chernikov * Returns 0 on success. 2056b074b7bbSAlexander V. Chernikov */ 2057b074b7bbSAlexander V. Chernikov static int 20589490a627SAlexander V. Chernikov bind_table_rule(struct ip_fw_chain *ch, struct ip_fw *rule, 20599490a627SAlexander V. Chernikov struct rule_check_info *ci, struct obj_idx **oib, struct tid_info *ti) 2060b074b7bbSAlexander V. Chernikov { 2061b074b7bbSAlexander V. Chernikov struct table_config *tc; 20629490a627SAlexander V. Chernikov struct namedobj_instance *ni; 20639490a627SAlexander V. Chernikov struct named_object *no; 20649490a627SAlexander V. Chernikov int error, l, cmdlen; 20659490a627SAlexander V. Chernikov ipfw_insn *cmd; 20669490a627SAlexander V. Chernikov struct obj_idx *pidx, *p; 20679490a627SAlexander V. Chernikov 20689490a627SAlexander V. Chernikov pidx = *oib; 20699490a627SAlexander V. Chernikov l = rule->cmd_len; 20709490a627SAlexander V. Chernikov cmd = rule->cmd; 20719490a627SAlexander V. Chernikov cmdlen = 0; 20729490a627SAlexander V. Chernikov error = 0; 20739490a627SAlexander V. Chernikov 20749490a627SAlexander V. Chernikov IPFW_UH_WLOCK(ch); 20759490a627SAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 20769490a627SAlexander V. Chernikov 20779490a627SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 20789490a627SAlexander V. Chernikov cmdlen = F_LEN(cmd); 20799490a627SAlexander V. Chernikov 20809490a627SAlexander V. Chernikov if (classify_table_opcode(cmd, &ti->uidx, &ti->type) != 0) 20819490a627SAlexander V. Chernikov continue; 2082b074b7bbSAlexander V. Chernikov 2083b074b7bbSAlexander V. Chernikov pidx->uidx = ti->uidx; 2084b074b7bbSAlexander V. Chernikov pidx->type = ti->type; 2085b074b7bbSAlexander V. Chernikov 20869490a627SAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 20879490a627SAlexander V. Chernikov if (tc->no.type != ti->type) { 20889490a627SAlexander V. Chernikov /* Incompatible types */ 20899490a627SAlexander V. Chernikov error = EINVAL; 20909490a627SAlexander V. Chernikov break; 20919490a627SAlexander V. Chernikov } 20929f7d47b0SAlexander V. Chernikov 20939490a627SAlexander V. Chernikov /* Reference found table and save kidx */ 20949490a627SAlexander V. Chernikov tc->no.refcnt++; 20959490a627SAlexander V. Chernikov pidx->kidx = tc->no.kidx; 20969490a627SAlexander V. Chernikov pidx++; 20979490a627SAlexander V. Chernikov continue; 20989490a627SAlexander V. Chernikov } 20999490a627SAlexander V. Chernikov 21009490a627SAlexander V. Chernikov /* Table not found. Allocate new index and save for later */ 2101ac35ff17SAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, &pidx->kidx) != 0) { 2102ac35ff17SAlexander V. Chernikov printf("Unable to allocate table %s index in set %u." 2103b074b7bbSAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 2104ac35ff17SAlexander V. Chernikov "", ti->set); 21059490a627SAlexander V. Chernikov error = EBUSY; 21069490a627SAlexander V. Chernikov break; 2107b074b7bbSAlexander V. Chernikov } 2108b074b7bbSAlexander V. Chernikov 2109b074b7bbSAlexander V. Chernikov ci->new_tables++; 21109490a627SAlexander V. Chernikov pidx->new = 1; 21119490a627SAlexander V. Chernikov pidx++; 2112b074b7bbSAlexander V. Chernikov } 2113b074b7bbSAlexander V. Chernikov 21149490a627SAlexander V. Chernikov if (error != 0) { 21159490a627SAlexander V. Chernikov /* Unref everything we have already done */ 21169490a627SAlexander V. Chernikov for (p = *oib; p < pidx; p++) { 21179490a627SAlexander V. Chernikov if (p->new != 0) { 2118ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, p->kidx); 21199490a627SAlexander V. Chernikov continue; 21209490a627SAlexander V. Chernikov } 2121b074b7bbSAlexander V. Chernikov 21229490a627SAlexander V. Chernikov /* Find & unref by existing idx */ 2123ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, p->kidx); 21249490a627SAlexander V. Chernikov KASSERT(no != NULL, ("Ref'd table %d disappeared", 21259490a627SAlexander V. Chernikov p->kidx)); 2126b074b7bbSAlexander V. Chernikov 21279490a627SAlexander V. Chernikov no->refcnt--; 21289490a627SAlexander V. Chernikov } 21299490a627SAlexander V. Chernikov } 21309490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 2131b074b7bbSAlexander V. Chernikov 21329490a627SAlexander V. Chernikov *oib = pidx; 21339490a627SAlexander V. Chernikov 21349490a627SAlexander V. Chernikov return (error); 2135b074b7bbSAlexander V. Chernikov } 2136b074b7bbSAlexander V. Chernikov 2137b074b7bbSAlexander V. Chernikov /* 2138b074b7bbSAlexander V. Chernikov * Compatibility function for old ipfw(8) binaries. 2139b074b7bbSAlexander V. Chernikov * Rewrites table kernel indices with userland ones. 2140b074b7bbSAlexander V. Chernikov * Works for \d+ talbes only (e.g. for tables, converted 2141b074b7bbSAlexander V. Chernikov * from old numbered system calls). 2142b074b7bbSAlexander V. Chernikov * 2143b074b7bbSAlexander V. Chernikov * Returns 0 on success. 2144b074b7bbSAlexander V. Chernikov * Raises error on any other tables. 2145b074b7bbSAlexander V. Chernikov */ 2146b074b7bbSAlexander V. Chernikov int 21477e767c79SAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw_rule0 *rule) 2148b074b7bbSAlexander V. Chernikov { 21491832a7b3SAlexander V. Chernikov int cmdlen, error, l; 2150b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 21511832a7b3SAlexander V. Chernikov uint16_t kidx, uidx; 2152b074b7bbSAlexander V. Chernikov uint8_t type; 2153b074b7bbSAlexander V. Chernikov struct named_object *no; 2154b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2155b074b7bbSAlexander V. Chernikov 2156b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 21571832a7b3SAlexander V. Chernikov error = 0; 2158b074b7bbSAlexander V. Chernikov 2159b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 2160b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 2161b074b7bbSAlexander V. Chernikov cmdlen = 0; 2162b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2163b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2164b074b7bbSAlexander V. Chernikov 2165b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2166b074b7bbSAlexander V. Chernikov continue; 2167b074b7bbSAlexander V. Chernikov 2168ac35ff17SAlexander V. Chernikov if ((no = ipfw_objhash_lookup_kidx(ni, kidx)) == NULL) 2169b074b7bbSAlexander V. Chernikov return (1); 2170b074b7bbSAlexander V. Chernikov 21711832a7b3SAlexander V. Chernikov uidx = no->uidx; 21721832a7b3SAlexander V. Chernikov if (no->compat == 0) { 2173b074b7bbSAlexander V. Chernikov 21741832a7b3SAlexander V. Chernikov /* 21751832a7b3SAlexander V. Chernikov * We are called via legacy opcode. 21761832a7b3SAlexander V. Chernikov * Save error and show table as fake number 21771832a7b3SAlexander V. Chernikov * not to make ipfw(8) hang. 21781832a7b3SAlexander V. Chernikov */ 21791832a7b3SAlexander V. Chernikov uidx = 65535; 21801832a7b3SAlexander V. Chernikov error = 2; 2181b074b7bbSAlexander V. Chernikov } 2182b074b7bbSAlexander V. Chernikov 21831832a7b3SAlexander V. Chernikov update_table_opcode(cmd, uidx); 21841832a7b3SAlexander V. Chernikov } 21851832a7b3SAlexander V. Chernikov 21861832a7b3SAlexander V. Chernikov return (error); 2187b074b7bbSAlexander V. Chernikov } 2188b074b7bbSAlexander V. Chernikov 2189563b5ab1SAlexander V. Chernikov /* 2190563b5ab1SAlexander V. Chernikov * Sets every table kidx in @bmask which is used in rule @rule. 2191563b5ab1SAlexander V. Chernikov * 2192563b5ab1SAlexander V. Chernikov * Returns number of newly-referenced tables. 2193563b5ab1SAlexander V. Chernikov */ 2194563b5ab1SAlexander V. Chernikov int 2195563b5ab1SAlexander V. Chernikov ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule, 2196563b5ab1SAlexander V. Chernikov uint32_t *bmask) 2197563b5ab1SAlexander V. Chernikov { 2198563b5ab1SAlexander V. Chernikov int cmdlen, l, count; 2199563b5ab1SAlexander V. Chernikov ipfw_insn *cmd; 2200563b5ab1SAlexander V. Chernikov uint16_t kidx; 2201563b5ab1SAlexander V. Chernikov uint8_t type; 2202563b5ab1SAlexander V. Chernikov 2203563b5ab1SAlexander V. Chernikov l = rule->cmd_len; 2204563b5ab1SAlexander V. Chernikov cmd = rule->cmd; 2205563b5ab1SAlexander V. Chernikov cmdlen = 0; 2206563b5ab1SAlexander V. Chernikov count = 0; 2207563b5ab1SAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2208563b5ab1SAlexander V. Chernikov cmdlen = F_LEN(cmd); 2209563b5ab1SAlexander V. Chernikov 2210563b5ab1SAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2211563b5ab1SAlexander V. Chernikov continue; 2212563b5ab1SAlexander V. Chernikov 2213563b5ab1SAlexander V. Chernikov if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0) 2214563b5ab1SAlexander V. Chernikov count++; 2215563b5ab1SAlexander V. Chernikov 2216563b5ab1SAlexander V. Chernikov bmask[kidx / 32] |= 1 << (kidx % 32); 2217563b5ab1SAlexander V. Chernikov } 2218563b5ab1SAlexander V. Chernikov 2219563b5ab1SAlexander V. Chernikov return (count); 2220563b5ab1SAlexander V. Chernikov } 2221563b5ab1SAlexander V. Chernikov 2222563b5ab1SAlexander V. Chernikov 2223b074b7bbSAlexander V. Chernikov 2224b074b7bbSAlexander V. Chernikov /* 2225b074b7bbSAlexander V. Chernikov * Checks is opcode is referencing table of appropriate type. 2226b074b7bbSAlexander V. Chernikov * Adds reference count for found table if true. 2227b074b7bbSAlexander V. Chernikov * Rewrites user-supplied opcode values with kernel ones. 2228b074b7bbSAlexander V. Chernikov * 2229b074b7bbSAlexander V. Chernikov * Returns 0 on success and appropriate error code otherwise. 2230b074b7bbSAlexander V. Chernikov */ 2231b074b7bbSAlexander V. Chernikov int 2232b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, 2233b074b7bbSAlexander V. Chernikov struct rule_check_info *ci) 2234b074b7bbSAlexander V. Chernikov { 2235b074b7bbSAlexander V. Chernikov int cmdlen, error, ftype, l; 2236b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 2237b074b7bbSAlexander V. Chernikov uint16_t uidx; 2238b074b7bbSAlexander V. Chernikov uint8_t type; 2239b074b7bbSAlexander V. Chernikov struct table_config *tc; 22409f7d47b0SAlexander V. Chernikov struct table_algo *ta; 2241b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2242b074b7bbSAlexander V. Chernikov struct named_object *no, *no_n, *no_tmp; 22439490a627SAlexander V. Chernikov struct obj_idx *p, *pidx_first, *pidx_last; 2244b074b7bbSAlexander V. Chernikov struct namedobjects_head nh; 2245b074b7bbSAlexander V. Chernikov struct tid_info ti; 2246b074b7bbSAlexander V. Chernikov 2247b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 2248b074b7bbSAlexander V. Chernikov 22499490a627SAlexander V. Chernikov /* Prepare queue to store configs */ 22509490a627SAlexander V. Chernikov TAILQ_INIT(&nh); 22519490a627SAlexander V. Chernikov 2252b074b7bbSAlexander V. Chernikov /* 2253b074b7bbSAlexander V. Chernikov * Prepare an array for storing opcode indices. 2254b074b7bbSAlexander V. Chernikov * Use stack allocation by default. 2255b074b7bbSAlexander V. Chernikov */ 2256b074b7bbSAlexander V. Chernikov if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 2257b074b7bbSAlexander V. Chernikov /* Stack */ 22589490a627SAlexander V. Chernikov pidx_first = ci->obuf; 2259b074b7bbSAlexander V. Chernikov } else 22609490a627SAlexander V. Chernikov pidx_first = malloc(ci->table_opcodes * sizeof(struct obj_idx), 2261b074b7bbSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 2262b074b7bbSAlexander V. Chernikov 22639490a627SAlexander V. Chernikov pidx_last = pidx_first; 2264b074b7bbSAlexander V. Chernikov error = 0; 2265b074b7bbSAlexander V. Chernikov 2266b074b7bbSAlexander V. Chernikov type = 0; 2267b074b7bbSAlexander V. Chernikov ftype = 0; 2268b074b7bbSAlexander V. Chernikov 2269b074b7bbSAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 22701832a7b3SAlexander V. Chernikov 22711832a7b3SAlexander V. Chernikov /* 22721832a7b3SAlexander V. Chernikov * Use default set for looking up tables (old way) or 22731832a7b3SAlexander V. Chernikov * use set rule is assigned to (new way). 22741832a7b3SAlexander V. Chernikov */ 22751832a7b3SAlexander V. Chernikov ti.set = (V_fw_tables_sets != 0) ? ci->krule->set : 0; 22766c2997ffSAlexander V. Chernikov if (ci->ctlv != NULL) { 22776c2997ffSAlexander V. Chernikov ti.tlvs = (void *)(ci->ctlv + 1); 22786c2997ffSAlexander V. Chernikov ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv); 22796c2997ffSAlexander V. Chernikov } 2280b074b7bbSAlexander V. Chernikov 2281b074b7bbSAlexander V. Chernikov /* 22829490a627SAlexander V. Chernikov * Stage 1: reference existing tables, determine number 22839490a627SAlexander V. Chernikov * of tables we need to allocate and allocate indexes for each. 2284b074b7bbSAlexander V. Chernikov */ 22859490a627SAlexander V. Chernikov error = bind_table_rule(chain, ci->krule, ci, &pidx_last, &ti); 2286b074b7bbSAlexander V. Chernikov 2287b074b7bbSAlexander V. Chernikov if (error != 0) { 22889490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 22899490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 2290b074b7bbSAlexander V. Chernikov 2291b074b7bbSAlexander V. Chernikov return (error); 2292b074b7bbSAlexander V. Chernikov } 2293b074b7bbSAlexander V. Chernikov 2294b074b7bbSAlexander V. Chernikov /* 2295b074b7bbSAlexander V. Chernikov * Stage 2: allocate table configs for every non-existent table 2296b074b7bbSAlexander V. Chernikov */ 2297b074b7bbSAlexander V. Chernikov 22989f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 22999490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 2300b074b7bbSAlexander V. Chernikov if (p->new == 0) 2301b074b7bbSAlexander V. Chernikov continue; 2302b074b7bbSAlexander V. Chernikov 2303b074b7bbSAlexander V. Chernikov ti.uidx = p->uidx; 2304b074b7bbSAlexander V. Chernikov ti.type = p->type; 23059f7d47b0SAlexander V. Chernikov ti.atype = 0; 2306b074b7bbSAlexander V. Chernikov 23079490a627SAlexander V. Chernikov ta = find_table_algo(CHAIN_TO_TCFG(chain), &ti, NULL); 23089f7d47b0SAlexander V. Chernikov if (ta == NULL) { 23099f7d47b0SAlexander V. Chernikov error = ENOTSUP; 23109f7d47b0SAlexander V. Chernikov goto free; 23119f7d47b0SAlexander V. Chernikov } 2312914bffb6SAlexander V. Chernikov tc = alloc_table_config(chain, &ti, ta, NULL, 0, 231368394ec8SAlexander V. Chernikov IPFW_VTYPE_U32); 2314b074b7bbSAlexander V. Chernikov 2315b074b7bbSAlexander V. Chernikov if (tc == NULL) { 2316b074b7bbSAlexander V. Chernikov error = ENOMEM; 2317b074b7bbSAlexander V. Chernikov goto free; 2318b074b7bbSAlexander V. Chernikov } 2319b074b7bbSAlexander V. Chernikov 2320b074b7bbSAlexander V. Chernikov tc->no.kidx = p->kidx; 2321b074b7bbSAlexander V. Chernikov tc->no.refcnt = 1; 2322b074b7bbSAlexander V. Chernikov 2323b074b7bbSAlexander V. Chernikov /* Add to list */ 2324b074b7bbSAlexander V. Chernikov TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next); 2325b074b7bbSAlexander V. Chernikov } 2326b074b7bbSAlexander V. Chernikov 2327b074b7bbSAlexander V. Chernikov /* 2328b074b7bbSAlexander V. Chernikov * Stage 2.1: Check if we're going to create 2 tables 2329b074b7bbSAlexander V. Chernikov * with the same name, but different table types. 2330b074b7bbSAlexander V. Chernikov */ 2331b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no, &nh, nn_next) { 2332b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no_tmp, &nh, nn_next) { 23339490a627SAlexander V. Chernikov if (ipfw_objhash_same_name(ni, no, no_tmp) == 0) 2334b074b7bbSAlexander V. Chernikov continue; 2335b074b7bbSAlexander V. Chernikov if (no->type != no_tmp->type) { 2336b074b7bbSAlexander V. Chernikov error = EINVAL; 2337b074b7bbSAlexander V. Chernikov goto free; 2338b074b7bbSAlexander V. Chernikov } 2339b074b7bbSAlexander V. Chernikov } 2340b074b7bbSAlexander V. Chernikov } 23419f7d47b0SAlexander V. Chernikov } 2342b074b7bbSAlexander V. Chernikov 23439f7d47b0SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 23449f7d47b0SAlexander V. Chernikov 23459f7d47b0SAlexander V. Chernikov if (ci->new_tables > 0) { 2346b074b7bbSAlexander V. Chernikov /* 2347b074b7bbSAlexander V. Chernikov * Stage 3: link & reference new table configs 2348b074b7bbSAlexander V. Chernikov */ 2349b074b7bbSAlexander V. Chernikov 2350b074b7bbSAlexander V. Chernikov 2351b074b7bbSAlexander V. Chernikov /* 2352b074b7bbSAlexander V. Chernikov * Step 3.1: Check if some tables we need to create have been 2353b074b7bbSAlexander V. Chernikov * already created with different table type. 2354b074b7bbSAlexander V. Chernikov */ 2355b074b7bbSAlexander V. Chernikov 2356b074b7bbSAlexander V. Chernikov error = 0; 2357b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2358b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 2359b074b7bbSAlexander V. Chernikov if (no_n == NULL) 2360b074b7bbSAlexander V. Chernikov continue; 2361b074b7bbSAlexander V. Chernikov 2362b074b7bbSAlexander V. Chernikov if (no_n->type != no->type) { 2363b074b7bbSAlexander V. Chernikov error = EINVAL; 2364b074b7bbSAlexander V. Chernikov break; 2365b074b7bbSAlexander V. Chernikov } 2366b074b7bbSAlexander V. Chernikov 2367b074b7bbSAlexander V. Chernikov } 2368b074b7bbSAlexander V. Chernikov 2369b074b7bbSAlexander V. Chernikov if (error != 0) { 2370b074b7bbSAlexander V. Chernikov /* 2371b074b7bbSAlexander V. Chernikov * Someone has allocated table with different table type. 2372b074b7bbSAlexander V. Chernikov * We have to rollback everything. 2373b074b7bbSAlexander V. Chernikov */ 2374b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 2375b074b7bbSAlexander V. Chernikov goto free; 2376b074b7bbSAlexander V. Chernikov } 2377b074b7bbSAlexander V. Chernikov 2378b074b7bbSAlexander V. Chernikov /* 23799f7d47b0SAlexander V. Chernikov * Attach new tables. 23809f7d47b0SAlexander V. Chernikov * We need to set table pointers for each new table, 2381b074b7bbSAlexander V. Chernikov * so we have to acquire main WLOCK. 2382b074b7bbSAlexander V. Chernikov */ 2383b074b7bbSAlexander V. Chernikov IPFW_WLOCK(chain); 2384b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2385b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 2386b074b7bbSAlexander V. Chernikov 23879490a627SAlexander V. Chernikov if (no_n == NULL) { 23889490a627SAlexander V. Chernikov /* New table. Attach to runtime hash */ 23899490a627SAlexander V. Chernikov TAILQ_REMOVE(&nh, no, nn_next); 23909490a627SAlexander V. Chernikov link_table(chain, (struct table_config *)no); 2391b074b7bbSAlexander V. Chernikov continue; 2392b074b7bbSAlexander V. Chernikov } 2393b074b7bbSAlexander V. Chernikov 23949490a627SAlexander V. Chernikov /* 23959490a627SAlexander V. Chernikov * Newly-allocated table with the same type. 23969490a627SAlexander V. Chernikov * Reference it and update out @pidx array 23979490a627SAlexander V. Chernikov * rewrite info. 23989490a627SAlexander V. Chernikov */ 23999490a627SAlexander V. Chernikov no_n->refcnt++; 24009490a627SAlexander V. Chernikov /* Keep oib array in sync: update kidx */ 24019490a627SAlexander V. Chernikov for (p = pidx_first; p < pidx_last; p++) { 24029490a627SAlexander V. Chernikov if (p->kidx != no->kidx) 24039490a627SAlexander V. Chernikov continue; 24049490a627SAlexander V. Chernikov /* Update kidx */ 24059490a627SAlexander V. Chernikov p->kidx = no_n->kidx; 24069490a627SAlexander V. Chernikov break; 24079490a627SAlexander V. Chernikov } 2408b074b7bbSAlexander V. Chernikov } 2409b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(chain); 24109f7d47b0SAlexander V. Chernikov } 2411b074b7bbSAlexander V. Chernikov 2412b074b7bbSAlexander V. Chernikov /* Perform rule rewrite */ 2413b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 2414b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 2415b074b7bbSAlexander V. Chernikov cmdlen = 0; 24169490a627SAlexander V. Chernikov p = pidx_first; 2417b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2418b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2419b074b7bbSAlexander V. Chernikov 2420b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &uidx, &type) != 0) 2421b074b7bbSAlexander V. Chernikov continue; 24229490a627SAlexander V. Chernikov update_table_opcode(cmd, p->kidx); 24239490a627SAlexander V. Chernikov p++; 2424b074b7bbSAlexander V. Chernikov } 2425b074b7bbSAlexander V. Chernikov 2426b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 2427b074b7bbSAlexander V. Chernikov 2428b074b7bbSAlexander V. Chernikov error = 0; 2429b074b7bbSAlexander V. Chernikov 2430b074b7bbSAlexander V. Chernikov /* 2431b074b7bbSAlexander V. Chernikov * Stage 4: free resources 2432b074b7bbSAlexander V. Chernikov */ 2433b074b7bbSAlexander V. Chernikov free: 24349490a627SAlexander V. Chernikov if (!TAILQ_EMPTY(&nh)) { 24359490a627SAlexander V. Chernikov /* Free indexes first */ 24369490a627SAlexander V. Chernikov IPFW_UH_WLOCK(chain); 24379490a627SAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 2438ac35ff17SAlexander V. Chernikov ipfw_objhash_free_idx(ni, no->kidx); 24399490a627SAlexander V. Chernikov } 24409490a627SAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 24419490a627SAlexander V. Chernikov /* Free configs */ 2442b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) 2443b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 24449490a627SAlexander V. Chernikov } 2445b074b7bbSAlexander V. Chernikov 24469490a627SAlexander V. Chernikov if (pidx_first != ci->obuf) 24479490a627SAlexander V. Chernikov free(pidx_first, M_IPFW); 2448b074b7bbSAlexander V. Chernikov 2449b074b7bbSAlexander V. Chernikov return (error); 2450b074b7bbSAlexander V. Chernikov } 2451b074b7bbSAlexander V. Chernikov 2452b074b7bbSAlexander V. Chernikov /* 2453b074b7bbSAlexander V. Chernikov * Remove references from every table used in @rule. 2454b074b7bbSAlexander V. Chernikov */ 2455b074b7bbSAlexander V. Chernikov void 2456b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule) 2457b074b7bbSAlexander V. Chernikov { 2458b074b7bbSAlexander V. Chernikov int cmdlen, l; 2459b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 2460b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 2461b074b7bbSAlexander V. Chernikov struct named_object *no; 2462b074b7bbSAlexander V. Chernikov uint16_t kidx; 2463b074b7bbSAlexander V. Chernikov uint8_t type; 2464b074b7bbSAlexander V. Chernikov 2465b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 2466b074b7bbSAlexander V. Chernikov 2467b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 2468b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 2469b074b7bbSAlexander V. Chernikov cmdlen = 0; 2470b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2471b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 2472b074b7bbSAlexander V. Chernikov 2473b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 2474b074b7bbSAlexander V. Chernikov continue; 2475b074b7bbSAlexander V. Chernikov 2476ac35ff17SAlexander V. Chernikov no = ipfw_objhash_lookup_kidx(ni, kidx); 2477b074b7bbSAlexander V. Chernikov 2478b074b7bbSAlexander V. Chernikov KASSERT(no != NULL, ("table id %d not found", kidx)); 2479b074b7bbSAlexander V. Chernikov KASSERT(no->type == type, ("wrong type %d (%d) for table id %d", 2480b074b7bbSAlexander V. Chernikov no->type, type, kidx)); 2481b074b7bbSAlexander V. Chernikov KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 2482b074b7bbSAlexander V. Chernikov kidx, no->refcnt)); 2483b074b7bbSAlexander V. Chernikov 2484b074b7bbSAlexander V. Chernikov no->refcnt--; 2485b074b7bbSAlexander V. Chernikov } 2486b074b7bbSAlexander V. Chernikov } 2487b074b7bbSAlexander V. Chernikov 2488b074b7bbSAlexander V. Chernikov 2489b074b7bbSAlexander V. Chernikov /* 2490b074b7bbSAlexander V. Chernikov * Removes table bindings for every rule in rule chain @head. 2491b074b7bbSAlexander V. Chernikov */ 2492b074b7bbSAlexander V. Chernikov void 2493b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head) 2494b074b7bbSAlexander V. Chernikov { 2495b074b7bbSAlexander V. Chernikov struct ip_fw *rule; 2496b074b7bbSAlexander V. Chernikov 2497b074b7bbSAlexander V. Chernikov while ((rule = head) != NULL) { 2498b074b7bbSAlexander V. Chernikov head = head->x_next; 2499b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(chain, rule); 2500b074b7bbSAlexander V. Chernikov } 2501b074b7bbSAlexander V. Chernikov } 2502b074b7bbSAlexander V. Chernikov 2503b074b7bbSAlexander V. Chernikov 25043b3a8eb9SGleb Smirnoff /* end of file */ 2505