13b3a8eb9SGleb Smirnoff /*- 23b3a8eb9SGleb Smirnoff * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. 33b3a8eb9SGleb Smirnoff * 43b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 53b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions 63b3a8eb9SGleb Smirnoff * are met: 73b3a8eb9SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 83b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 93b3a8eb9SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 103b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 113b3a8eb9SGleb Smirnoff * documentation and/or other materials provided with the distribution. 123b3a8eb9SGleb Smirnoff * 133b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 143b3a8eb9SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 153b3a8eb9SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 163b3a8eb9SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 173b3a8eb9SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 183b3a8eb9SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 193b3a8eb9SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 203b3a8eb9SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 213b3a8eb9SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 223b3a8eb9SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 233b3a8eb9SGleb Smirnoff * SUCH DAMAGE. 243b3a8eb9SGleb Smirnoff */ 253b3a8eb9SGleb Smirnoff 263b3a8eb9SGleb Smirnoff #include <sys/cdefs.h> 273b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$"); 283b3a8eb9SGleb Smirnoff 293b3a8eb9SGleb Smirnoff /* 303b3a8eb9SGleb Smirnoff * Lookup table support for ipfw 313b3a8eb9SGleb Smirnoff * 323b3a8eb9SGleb Smirnoff * Lookup tables are implemented (at the moment) using the radix 333b3a8eb9SGleb Smirnoff * tree used for routing tables. Tables store key-value entries, where 343b3a8eb9SGleb Smirnoff * keys are network prefixes (addr/masklen), and values are integers. 353b3a8eb9SGleb Smirnoff * As a degenerate case we can interpret keys as 32-bit integers 363b3a8eb9SGleb Smirnoff * (with a /32 mask). 373b3a8eb9SGleb Smirnoff * 383b3a8eb9SGleb Smirnoff * The table is protected by the IPFW lock even for manipulation coming 393b3a8eb9SGleb Smirnoff * from userland, because operations are typically fast. 403b3a8eb9SGleb Smirnoff */ 413b3a8eb9SGleb Smirnoff 423b3a8eb9SGleb Smirnoff #include "opt_ipfw.h" 433b3a8eb9SGleb Smirnoff #include "opt_inet.h" 443b3a8eb9SGleb Smirnoff #ifndef INET 453b3a8eb9SGleb Smirnoff #error IPFIREWALL requires INET. 463b3a8eb9SGleb Smirnoff #endif /* INET */ 473b3a8eb9SGleb Smirnoff #include "opt_inet6.h" 483b3a8eb9SGleb Smirnoff 493b3a8eb9SGleb Smirnoff #include <sys/param.h> 503b3a8eb9SGleb Smirnoff #include <sys/systm.h> 513b3a8eb9SGleb Smirnoff #include <sys/malloc.h> 523b3a8eb9SGleb Smirnoff #include <sys/kernel.h> 533b3a8eb9SGleb Smirnoff #include <sys/lock.h> 543b3a8eb9SGleb Smirnoff #include <sys/rwlock.h> 553b3a8eb9SGleb Smirnoff #include <sys/socket.h> 563b3a8eb9SGleb Smirnoff #include <sys/queue.h> 573b3a8eb9SGleb Smirnoff #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 583b3a8eb9SGleb Smirnoff #include <net/radix.h> 593b3a8eb9SGleb Smirnoff #include <net/route.h> 603b3a8eb9SGleb Smirnoff #include <net/vnet.h> 613b3a8eb9SGleb Smirnoff 623b3a8eb9SGleb Smirnoff #include <netinet/in.h> 633b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 643b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h> 653b3a8eb9SGleb Smirnoff 663b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h> 673b3a8eb9SGleb Smirnoff 683b3a8eb9SGleb Smirnoff #ifdef MAC 693b3a8eb9SGleb Smirnoff #include <security/mac/mac_framework.h> 703b3a8eb9SGleb Smirnoff #endif 713b3a8eb9SGleb Smirnoff 723b3a8eb9SGleb Smirnoff static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 733b3a8eb9SGleb Smirnoff 743b3a8eb9SGleb Smirnoff struct table_entry { 753b3a8eb9SGleb Smirnoff struct radix_node rn[2]; 763b3a8eb9SGleb Smirnoff struct sockaddr_in addr, mask; 773b3a8eb9SGleb Smirnoff u_int32_t value; 783b3a8eb9SGleb Smirnoff }; 793b3a8eb9SGleb Smirnoff 803b3a8eb9SGleb Smirnoff struct xaddr_iface { 813b3a8eb9SGleb Smirnoff uint8_t if_len; /* length of this struct */ 823b3a8eb9SGleb Smirnoff uint8_t pad[7]; /* Align name */ 833b3a8eb9SGleb Smirnoff char ifname[IF_NAMESIZE]; /* Interface name */ 843b3a8eb9SGleb Smirnoff }; 853b3a8eb9SGleb Smirnoff 863b3a8eb9SGleb Smirnoff struct table_xentry { 873b3a8eb9SGleb Smirnoff struct radix_node rn[2]; 883b3a8eb9SGleb Smirnoff union { 893b3a8eb9SGleb Smirnoff #ifdef INET6 903b3a8eb9SGleb Smirnoff struct sockaddr_in6 addr6; 913b3a8eb9SGleb Smirnoff #endif 923b3a8eb9SGleb Smirnoff struct xaddr_iface iface; 933b3a8eb9SGleb Smirnoff } a; 943b3a8eb9SGleb Smirnoff union { 953b3a8eb9SGleb Smirnoff #ifdef INET6 963b3a8eb9SGleb Smirnoff struct sockaddr_in6 mask6; 973b3a8eb9SGleb Smirnoff #endif 983b3a8eb9SGleb Smirnoff struct xaddr_iface ifmask; 993b3a8eb9SGleb Smirnoff } m; 1003b3a8eb9SGleb Smirnoff u_int32_t value; 1013b3a8eb9SGleb Smirnoff }; 1023b3a8eb9SGleb Smirnoff 1033b3a8eb9SGleb Smirnoff /* 104b074b7bbSAlexander V. Chernikov * Table has the following `type` concepts: 105b074b7bbSAlexander V. Chernikov * 106b074b7bbSAlexander V. Chernikov * `type` represents lookup key type (cidr, ifp, uid, etc..) 107b074b7bbSAlexander V. Chernikov * `ftype` is pure userland field helping to properly format table data 108b074b7bbSAlexander V. Chernikov * `atype` represents exact lookup algorithm for given tabletype. 109b074b7bbSAlexander V. Chernikov * For example, we can use more efficient search schemes if we plan 110b074b7bbSAlexander V. Chernikov * to use some specific table for storing host-routes only. 111b074b7bbSAlexander V. Chernikov * 112b074b7bbSAlexander V. Chernikov */ 113b074b7bbSAlexander V. Chernikov struct table_config { 114b074b7bbSAlexander V. Chernikov struct named_object no; 115b074b7bbSAlexander V. Chernikov uint8_t ftype; /* format table type */ 116b074b7bbSAlexander V. Chernikov uint8_t atype; /* algorith type */ 117b074b7bbSAlexander V. Chernikov uint8_t linked; /* 1 if already linked */ 118b074b7bbSAlexander V. Chernikov uint8_t spare0; 119b074b7bbSAlexander V. Chernikov uint32_t count; /* Number of records */ 120b074b7bbSAlexander V. Chernikov char tablename[64]; /* table name */ 121b074b7bbSAlexander V. Chernikov void *state; /* Store some state if needed */ 122b074b7bbSAlexander V. Chernikov void *xstate; 123b074b7bbSAlexander V. Chernikov }; 124b074b7bbSAlexander V. Chernikov #define TABLE_SET(set) ((V_fw_tables_sets != 0) ? set : 0) 125b074b7bbSAlexander V. Chernikov 126b074b7bbSAlexander V. Chernikov struct tables_config { 127b074b7bbSAlexander V. Chernikov struct namedobj_instance *namehash; 128b074b7bbSAlexander V. Chernikov }; 129b074b7bbSAlexander V. Chernikov 130b074b7bbSAlexander V. Chernikov static struct table_config *find_table(struct namedobj_instance *ni, 131b074b7bbSAlexander V. Chernikov struct tid_info *ti); 132b074b7bbSAlexander V. Chernikov static struct table_config *alloc_table_config(struct namedobj_instance *ni, 133b074b7bbSAlexander V. Chernikov struct tid_info *ti); 134b074b7bbSAlexander V. Chernikov static void free_table_config(struct namedobj_instance *ni, 135b074b7bbSAlexander V. Chernikov struct table_config *tc); 136b074b7bbSAlexander V. Chernikov static void link_table(struct ip_fw_chain *chain, struct table_config *tc); 137b074b7bbSAlexander V. Chernikov static void unlink_table(struct ip_fw_chain *chain, struct table_config *tc); 138b074b7bbSAlexander V. Chernikov static int alloc_table_state(void **state, void **xstate, uint8_t type); 139b074b7bbSAlexander V. Chernikov static void free_table_state(void **state, void **xstate, uint8_t type); 140b074b7bbSAlexander V. Chernikov 141b074b7bbSAlexander V. Chernikov 142b074b7bbSAlexander V. Chernikov #define CHAIN_TO_TCFG(chain) ((struct tables_config *)(chain)->tblcfg) 143b074b7bbSAlexander V. Chernikov #define CHAIN_TO_NI(chain) (CHAIN_TO_TCFG(chain)->namehash) 144b074b7bbSAlexander V. Chernikov 145b074b7bbSAlexander V. Chernikov 146b074b7bbSAlexander V. Chernikov /* 1473b3a8eb9SGleb Smirnoff * The radix code expects addr and mask to be array of bytes, 1483b3a8eb9SGleb Smirnoff * with the first byte being the length of the array. rn_inithead 1493b3a8eb9SGleb Smirnoff * is called with the offset in bits of the lookup key within the 1503b3a8eb9SGleb Smirnoff * array. If we use a sockaddr_in as the underlying type, 1513b3a8eb9SGleb Smirnoff * sin_len is conveniently located at offset 0, sin_addr is at 1523b3a8eb9SGleb Smirnoff * offset 4 and normally aligned. 1533b3a8eb9SGleb Smirnoff * But for portability, let's avoid assumption and make the code explicit 1543b3a8eb9SGleb Smirnoff */ 1553b3a8eb9SGleb Smirnoff #define KEY_LEN(v) *((uint8_t *)&(v)) 1563b3a8eb9SGleb Smirnoff #define KEY_OFS (8*offsetof(struct sockaddr_in, sin_addr)) 1573b3a8eb9SGleb Smirnoff /* 1583b3a8eb9SGleb Smirnoff * Do not require radix to compare more than actual IPv4/IPv6 address 1593b3a8eb9SGleb Smirnoff */ 1603b3a8eb9SGleb Smirnoff #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t)) 1613b3a8eb9SGleb Smirnoff #define KEY_LEN_INET6 (offsetof(struct sockaddr_in6, sin6_addr) + sizeof(struct in6_addr)) 1623b3a8eb9SGleb Smirnoff #define KEY_LEN_IFACE (offsetof(struct xaddr_iface, ifname)) 1633b3a8eb9SGleb Smirnoff 1643b3a8eb9SGleb Smirnoff #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr)) 1653b3a8eb9SGleb Smirnoff #define OFF_LEN_INET6 (8 * offsetof(struct sockaddr_in6, sin6_addr)) 1663b3a8eb9SGleb Smirnoff #define OFF_LEN_IFACE (8 * offsetof(struct xaddr_iface, ifname)) 1673b3a8eb9SGleb Smirnoff 1683b3a8eb9SGleb Smirnoff 169a3043eeeSDimitry Andric #ifdef INET6 1703b3a8eb9SGleb Smirnoff static inline void 1713b3a8eb9SGleb Smirnoff ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 1723b3a8eb9SGleb Smirnoff { 1733b3a8eb9SGleb Smirnoff uint32_t *cp; 1743b3a8eb9SGleb Smirnoff 1753b3a8eb9SGleb Smirnoff for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 1763b3a8eb9SGleb Smirnoff *cp++ = 0xFFFFFFFF; 1773b3a8eb9SGleb Smirnoff *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 1783b3a8eb9SGleb Smirnoff } 179a3043eeeSDimitry Andric #endif 1803b3a8eb9SGleb Smirnoff 1813b3a8eb9SGleb Smirnoff int 182b074b7bbSAlexander V. Chernikov ipfw_add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 183b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 1843b3a8eb9SGleb Smirnoff { 185b074b7bbSAlexander V. Chernikov struct radix_node_head *rnh; 1863b3a8eb9SGleb Smirnoff struct table_entry *ent; 1873b3a8eb9SGleb Smirnoff struct table_xentry *xent; 1883b3a8eb9SGleb Smirnoff struct radix_node *rn; 1893b3a8eb9SGleb Smirnoff in_addr_t addr; 1903b3a8eb9SGleb Smirnoff int offset; 1913b3a8eb9SGleb Smirnoff void *ent_ptr; 1923b3a8eb9SGleb Smirnoff struct sockaddr *addr_ptr, *mask_ptr; 193b074b7bbSAlexander V. Chernikov struct table_config *tc, *tc_new; 194b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1953b3a8eb9SGleb Smirnoff char c; 196b074b7bbSAlexander V. Chernikov uint8_t mlen; 197b074b7bbSAlexander V. Chernikov uint16_t kidx; 1983b3a8eb9SGleb Smirnoff 199b074b7bbSAlexander V. Chernikov if (ti->uidx >= V_fw_tables_max) 2003b3a8eb9SGleb Smirnoff return (EINVAL); 2013b3a8eb9SGleb Smirnoff 202b074b7bbSAlexander V. Chernikov mlen = tei->masklen; 203b074b7bbSAlexander V. Chernikov 204b074b7bbSAlexander V. Chernikov switch (ti->type) { 2053b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 206b074b7bbSAlexander V. Chernikov if (tei->plen == sizeof(in_addr_t)) { 2073b3a8eb9SGleb Smirnoff #ifdef INET 2083b3a8eb9SGleb Smirnoff /* IPv4 case */ 2093b3a8eb9SGleb Smirnoff if (mlen > 32) 2103b3a8eb9SGleb Smirnoff return (EINVAL); 2113b3a8eb9SGleb Smirnoff ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 212b074b7bbSAlexander V. Chernikov ent->value = tei->value; 2133b3a8eb9SGleb Smirnoff /* Set 'total' structure length */ 2143b3a8eb9SGleb Smirnoff KEY_LEN(ent->addr) = KEY_LEN_INET; 2153b3a8eb9SGleb Smirnoff KEY_LEN(ent->mask) = KEY_LEN_INET; 2163b3a8eb9SGleb Smirnoff /* Set offset of IPv4 address in bits */ 2173b3a8eb9SGleb Smirnoff offset = OFF_LEN_INET; 218b074b7bbSAlexander V. Chernikov ent->mask.sin_addr.s_addr = 219b074b7bbSAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 220b074b7bbSAlexander V. Chernikov addr = *((in_addr_t *)tei->paddr); 2213b3a8eb9SGleb Smirnoff ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr; 2223b3a8eb9SGleb Smirnoff /* Set pointers */ 2233b3a8eb9SGleb Smirnoff ent_ptr = ent; 2243b3a8eb9SGleb Smirnoff addr_ptr = (struct sockaddr *)&ent->addr; 2253b3a8eb9SGleb Smirnoff mask_ptr = (struct sockaddr *)&ent->mask; 2263b3a8eb9SGleb Smirnoff #endif 2273b3a8eb9SGleb Smirnoff #ifdef INET6 228b074b7bbSAlexander V. Chernikov } else if (tei->plen == sizeof(struct in6_addr)) { 2293b3a8eb9SGleb Smirnoff /* IPv6 case */ 2303b3a8eb9SGleb Smirnoff if (mlen > 128) 2313b3a8eb9SGleb Smirnoff return (EINVAL); 2323b3a8eb9SGleb Smirnoff xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 233b074b7bbSAlexander V. Chernikov xent->value = tei->value; 2343b3a8eb9SGleb Smirnoff /* Set 'total' structure length */ 2353b3a8eb9SGleb Smirnoff KEY_LEN(xent->a.addr6) = KEY_LEN_INET6; 2363b3a8eb9SGleb Smirnoff KEY_LEN(xent->m.mask6) = KEY_LEN_INET6; 2373b3a8eb9SGleb Smirnoff /* Set offset of IPv6 address in bits */ 2383b3a8eb9SGleb Smirnoff offset = OFF_LEN_INET6; 2393b3a8eb9SGleb Smirnoff ipv6_writemask(&xent->m.mask6.sin6_addr, mlen); 240b074b7bbSAlexander V. Chernikov memcpy(&xent->a.addr6.sin6_addr, tei->paddr, 241b074b7bbSAlexander V. Chernikov sizeof(struct in6_addr)); 2423b3a8eb9SGleb Smirnoff APPLY_MASK(&xent->a.addr6.sin6_addr, &xent->m.mask6.sin6_addr); 2433b3a8eb9SGleb Smirnoff /* Set pointers */ 2443b3a8eb9SGleb Smirnoff ent_ptr = xent; 2453b3a8eb9SGleb Smirnoff addr_ptr = (struct sockaddr *)&xent->a.addr6; 2463b3a8eb9SGleb Smirnoff mask_ptr = (struct sockaddr *)&xent->m.mask6; 2473b3a8eb9SGleb Smirnoff #endif 2483b3a8eb9SGleb Smirnoff } else { 2493b3a8eb9SGleb Smirnoff /* Unknown CIDR type */ 2503b3a8eb9SGleb Smirnoff return (EINVAL); 2513b3a8eb9SGleb Smirnoff } 2523b3a8eb9SGleb Smirnoff break; 2533b3a8eb9SGleb Smirnoff 2543b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 2553b3a8eb9SGleb Smirnoff /* Check if string is terminated */ 256b074b7bbSAlexander V. Chernikov c = ((char *)tei->paddr)[IF_NAMESIZE - 1]; 257b074b7bbSAlexander V. Chernikov ((char *)tei->paddr)[IF_NAMESIZE - 1] = '\0'; 258b074b7bbSAlexander V. Chernikov mlen = strlen((char *)tei->paddr); 259b074b7bbSAlexander V. Chernikov if ((mlen == IF_NAMESIZE - 1) && (c != '\0')) 2603b3a8eb9SGleb Smirnoff return (EINVAL); 2613b3a8eb9SGleb Smirnoff 2623b3a8eb9SGleb Smirnoff /* Include last \0 into comparison */ 2633b3a8eb9SGleb Smirnoff mlen++; 2643b3a8eb9SGleb Smirnoff 2653b3a8eb9SGleb Smirnoff xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 266b074b7bbSAlexander V. Chernikov xent->value = tei->value; 2673b3a8eb9SGleb Smirnoff /* Set 'total' structure length */ 2683b3a8eb9SGleb Smirnoff KEY_LEN(xent->a.iface) = KEY_LEN_IFACE + mlen; 2693b3a8eb9SGleb Smirnoff KEY_LEN(xent->m.ifmask) = KEY_LEN_IFACE + mlen; 2703b3a8eb9SGleb Smirnoff /* Set offset of interface name in bits */ 2713b3a8eb9SGleb Smirnoff offset = OFF_LEN_IFACE; 272b074b7bbSAlexander V. Chernikov memcpy(xent->a.iface.ifname, tei->paddr, mlen); 2733b3a8eb9SGleb Smirnoff /* Assume direct match */ 2743b3a8eb9SGleb Smirnoff /* TODO: Add interface pattern matching */ 2753b3a8eb9SGleb Smirnoff #if 0 2763b3a8eb9SGleb Smirnoff memset(xent->m.ifmask.ifname, 0xFF, IF_NAMESIZE); 2773b3a8eb9SGleb Smirnoff mask_ptr = (struct sockaddr *)&xent->m.ifmask; 2783b3a8eb9SGleb Smirnoff #endif 2793b3a8eb9SGleb Smirnoff /* Set pointers */ 2803b3a8eb9SGleb Smirnoff ent_ptr = xent; 2813b3a8eb9SGleb Smirnoff addr_ptr = (struct sockaddr *)&xent->a.iface; 2823b3a8eb9SGleb Smirnoff mask_ptr = NULL; 2833b3a8eb9SGleb Smirnoff break; 2843b3a8eb9SGleb Smirnoff 2853b3a8eb9SGleb Smirnoff default: 2863b3a8eb9SGleb Smirnoff return (EINVAL); 2873b3a8eb9SGleb Smirnoff } 2883b3a8eb9SGleb Smirnoff 289b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 2903b3a8eb9SGleb Smirnoff 291b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 2923b3a8eb9SGleb Smirnoff 293b074b7bbSAlexander V. Chernikov tc_new = NULL; 294b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 295b074b7bbSAlexander V. Chernikov /* Not found. We have to create new one */ 296b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 297b074b7bbSAlexander V. Chernikov 298b074b7bbSAlexander V. Chernikov tc_new = alloc_table_config(ni, ti); 299b074b7bbSAlexander V. Chernikov if (tc_new == NULL) 3003b3a8eb9SGleb Smirnoff return (ENOMEM); 3013b3a8eb9SGleb Smirnoff 302b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 303b074b7bbSAlexander V. Chernikov 304b074b7bbSAlexander V. Chernikov /* Check if table has already allocated by other thread */ 305b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) != NULL) { 306b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 307b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 308b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 3093b3a8eb9SGleb Smirnoff return (EINVAL); 3103b3a8eb9SGleb Smirnoff } 3113b3a8eb9SGleb Smirnoff } else { 3123b3a8eb9SGleb Smirnoff /* 313b074b7bbSAlexander V. Chernikov * New table. 314b074b7bbSAlexander V. Chernikov * Set tc_new to zero not to free it afterwards. 3153b3a8eb9SGleb Smirnoff */ 316b074b7bbSAlexander V. Chernikov tc = tc_new; 317b074b7bbSAlexander V. Chernikov tc_new = NULL; 318b074b7bbSAlexander V. Chernikov 319b074b7bbSAlexander V. Chernikov /* Allocate table index. */ 320b074b7bbSAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, ti->set, &kidx) != 0) { 321b074b7bbSAlexander V. Chernikov /* Index full. */ 322b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 323b074b7bbSAlexander V. Chernikov printf("Unable to allocate index for table %s." 324b074b7bbSAlexander V. Chernikov " Consider increasing " 325b074b7bbSAlexander V. Chernikov "net.inet.ip.fw.tables_max", 326b074b7bbSAlexander V. Chernikov tc->no.name); 327b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 328b074b7bbSAlexander V. Chernikov return (EBUSY); 3293b3a8eb9SGleb Smirnoff } 330b074b7bbSAlexander V. Chernikov /* Save kidx */ 331b074b7bbSAlexander V. Chernikov tc->no.kidx = kidx; 332b074b7bbSAlexander V. Chernikov } 333b074b7bbSAlexander V. Chernikov } else { 334b074b7bbSAlexander V. Chernikov /* We still have to check table type */ 335b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 336b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 337b074b7bbSAlexander V. Chernikov return (EINVAL); 338b074b7bbSAlexander V. Chernikov } 339b074b7bbSAlexander V. Chernikov } 340b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 341b074b7bbSAlexander V. Chernikov 342b074b7bbSAlexander V. Chernikov /* We've got valid table in @tc. Let's add data */ 343b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 344b074b7bbSAlexander V. Chernikov 345b074b7bbSAlexander V. Chernikov if (tc->linked == 0) { 346b074b7bbSAlexander V. Chernikov link_table(ch, tc); 347b074b7bbSAlexander V. Chernikov } 348b074b7bbSAlexander V. Chernikov 349b074b7bbSAlexander V. Chernikov /* XXX: Temporary until splitting add/del to per-type functions */ 350b074b7bbSAlexander V. Chernikov rnh = NULL; 351b074b7bbSAlexander V. Chernikov switch (ti->type) { 352b074b7bbSAlexander V. Chernikov case IPFW_TABLE_CIDR: 353b074b7bbSAlexander V. Chernikov if (tei->plen == sizeof(in_addr_t)) 354b074b7bbSAlexander V. Chernikov rnh = ch->tables[kidx]; 355b074b7bbSAlexander V. Chernikov else 356b074b7bbSAlexander V. Chernikov rnh = ch->xtables[kidx]; 357b074b7bbSAlexander V. Chernikov break; 358b074b7bbSAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 359b074b7bbSAlexander V. Chernikov rnh = ch->xtables[kidx]; 360b074b7bbSAlexander V. Chernikov break; 3613b3a8eb9SGleb Smirnoff } 3623b3a8eb9SGleb Smirnoff 3633b3a8eb9SGleb Smirnoff rn = rnh->rnh_addaddr(addr_ptr, mask_ptr, rnh, ent_ptr); 3643b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 365b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 366b074b7bbSAlexander V. Chernikov 367b074b7bbSAlexander V. Chernikov if (tc_new != NULL) 368b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 3693b3a8eb9SGleb Smirnoff 3703b3a8eb9SGleb Smirnoff if (rn == NULL) { 3713b3a8eb9SGleb Smirnoff free(ent_ptr, M_IPFW_TBL); 3723b3a8eb9SGleb Smirnoff return (EEXIST); 3733b3a8eb9SGleb Smirnoff } 374b074b7bbSAlexander V. Chernikov 3753b3a8eb9SGleb Smirnoff return (0); 3763b3a8eb9SGleb Smirnoff } 3773b3a8eb9SGleb Smirnoff 3783b3a8eb9SGleb Smirnoff int 379b074b7bbSAlexander V. Chernikov ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, 380b074b7bbSAlexander V. Chernikov struct tentry_info *tei) 3813b3a8eb9SGleb Smirnoff { 382b074b7bbSAlexander V. Chernikov struct radix_node_head *rnh; 3833b3a8eb9SGleb Smirnoff struct table_entry *ent; 3843b3a8eb9SGleb Smirnoff in_addr_t addr; 3853b3a8eb9SGleb Smirnoff struct sockaddr_in sa, mask; 3863b3a8eb9SGleb Smirnoff struct sockaddr *sa_ptr, *mask_ptr; 387b074b7bbSAlexander V. Chernikov struct table_config *tc; 388b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 3893b3a8eb9SGleb Smirnoff char c; 390b074b7bbSAlexander V. Chernikov uint8_t mlen; 391b074b7bbSAlexander V. Chernikov uint16_t kidx; 3923b3a8eb9SGleb Smirnoff 393b074b7bbSAlexander V. Chernikov if (ti->uidx >= V_fw_tables_max) 3943b3a8eb9SGleb Smirnoff return (EINVAL); 3953b3a8eb9SGleb Smirnoff 396b074b7bbSAlexander V. Chernikov mlen = tei->masklen; 397b074b7bbSAlexander V. Chernikov 398b074b7bbSAlexander V. Chernikov switch (ti->type) { 3993b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 400b074b7bbSAlexander V. Chernikov if (tei->plen == sizeof(in_addr_t)) { 4013b3a8eb9SGleb Smirnoff /* Set 'total' structure length */ 4023b3a8eb9SGleb Smirnoff KEY_LEN(sa) = KEY_LEN_INET; 4033b3a8eb9SGleb Smirnoff KEY_LEN(mask) = KEY_LEN_INET; 4043b3a8eb9SGleb Smirnoff mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 405b074b7bbSAlexander V. Chernikov addr = *((in_addr_t *)tei->paddr); 4063b3a8eb9SGleb Smirnoff sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 4073b3a8eb9SGleb Smirnoff sa_ptr = (struct sockaddr *)&sa; 4083b3a8eb9SGleb Smirnoff mask_ptr = (struct sockaddr *)&mask; 4093b3a8eb9SGleb Smirnoff #ifdef INET6 410b074b7bbSAlexander V. Chernikov } else if (tei->plen == sizeof(struct in6_addr)) { 4113b3a8eb9SGleb Smirnoff /* IPv6 case */ 4123b3a8eb9SGleb Smirnoff if (mlen > 128) 4133b3a8eb9SGleb Smirnoff return (EINVAL); 4143b3a8eb9SGleb Smirnoff struct sockaddr_in6 sa6, mask6; 4153b3a8eb9SGleb Smirnoff memset(&sa6, 0, sizeof(struct sockaddr_in6)); 4163b3a8eb9SGleb Smirnoff memset(&mask6, 0, sizeof(struct sockaddr_in6)); 4173b3a8eb9SGleb Smirnoff /* Set 'total' structure length */ 4183b3a8eb9SGleb Smirnoff KEY_LEN(sa6) = KEY_LEN_INET6; 4193b3a8eb9SGleb Smirnoff KEY_LEN(mask6) = KEY_LEN_INET6; 4203b3a8eb9SGleb Smirnoff ipv6_writemask(&mask6.sin6_addr, mlen); 421b074b7bbSAlexander V. Chernikov memcpy(&sa6.sin6_addr, tei->paddr, 422b074b7bbSAlexander V. Chernikov sizeof(struct in6_addr)); 4233b3a8eb9SGleb Smirnoff APPLY_MASK(&sa6.sin6_addr, &mask6.sin6_addr); 4243b3a8eb9SGleb Smirnoff sa_ptr = (struct sockaddr *)&sa6; 4253b3a8eb9SGleb Smirnoff mask_ptr = (struct sockaddr *)&mask6; 4263b3a8eb9SGleb Smirnoff #endif 4273b3a8eb9SGleb Smirnoff } else { 4283b3a8eb9SGleb Smirnoff /* Unknown CIDR type */ 4293b3a8eb9SGleb Smirnoff return (EINVAL); 4303b3a8eb9SGleb Smirnoff } 4313b3a8eb9SGleb Smirnoff break; 4323b3a8eb9SGleb Smirnoff 4333b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 4343b3a8eb9SGleb Smirnoff /* Check if string is terminated */ 435b074b7bbSAlexander V. Chernikov c = ((char *)tei->paddr)[IF_NAMESIZE - 1]; 436b074b7bbSAlexander V. Chernikov ((char *)tei->paddr)[IF_NAMESIZE - 1] = '\0'; 437b074b7bbSAlexander V. Chernikov mlen = strlen((char *)tei->paddr); 438b074b7bbSAlexander V. Chernikov if ((mlen == IF_NAMESIZE - 1) && (c != '\0')) 4393b3a8eb9SGleb Smirnoff return (EINVAL); 4403b3a8eb9SGleb Smirnoff 4413b3a8eb9SGleb Smirnoff struct xaddr_iface ifname, ifmask; 4423b3a8eb9SGleb Smirnoff memset(&ifname, 0, sizeof(ifname)); 4433b3a8eb9SGleb Smirnoff 4443b3a8eb9SGleb Smirnoff /* Include last \0 into comparison */ 4453b3a8eb9SGleb Smirnoff mlen++; 4463b3a8eb9SGleb Smirnoff 4473b3a8eb9SGleb Smirnoff /* Set 'total' structure length */ 4483b3a8eb9SGleb Smirnoff KEY_LEN(ifname) = KEY_LEN_IFACE + mlen; 4493b3a8eb9SGleb Smirnoff KEY_LEN(ifmask) = KEY_LEN_IFACE + mlen; 4503b3a8eb9SGleb Smirnoff /* Assume direct match */ 4513b3a8eb9SGleb Smirnoff /* FIXME: Add interface pattern matching */ 4523b3a8eb9SGleb Smirnoff #if 0 4533b3a8eb9SGleb Smirnoff memset(ifmask.ifname, 0xFF, IF_NAMESIZE); 4543b3a8eb9SGleb Smirnoff mask_ptr = (struct sockaddr *)&ifmask; 4553b3a8eb9SGleb Smirnoff #endif 4563b3a8eb9SGleb Smirnoff mask_ptr = NULL; 457b074b7bbSAlexander V. Chernikov memcpy(ifname.ifname, tei->paddr, mlen); 4583b3a8eb9SGleb Smirnoff /* Set pointers */ 4593b3a8eb9SGleb Smirnoff sa_ptr = (struct sockaddr *)&ifname; 4603b3a8eb9SGleb Smirnoff 4613b3a8eb9SGleb Smirnoff break; 4623b3a8eb9SGleb Smirnoff 4633b3a8eb9SGleb Smirnoff default: 4643b3a8eb9SGleb Smirnoff return (EINVAL); 4653b3a8eb9SGleb Smirnoff } 4663b3a8eb9SGleb Smirnoff 467b074b7bbSAlexander V. Chernikov IPFW_UH_RLOCK(ch); 468b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 469b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 470b074b7bbSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 4713b3a8eb9SGleb Smirnoff return (ESRCH); 4723b3a8eb9SGleb Smirnoff } 4733b3a8eb9SGleb Smirnoff 474b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) { 475b074b7bbSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 4763b3a8eb9SGleb Smirnoff return (EINVAL); 4773b3a8eb9SGleb Smirnoff } 478b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 479b074b7bbSAlexander V. Chernikov 480b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 481b074b7bbSAlexander V. Chernikov 482b074b7bbSAlexander V. Chernikov rnh = NULL; 483b074b7bbSAlexander V. Chernikov switch (ti->type) { 484b074b7bbSAlexander V. Chernikov case IPFW_TABLE_CIDR: 485b074b7bbSAlexander V. Chernikov if (tei->plen == sizeof(in_addr_t)) 486b074b7bbSAlexander V. Chernikov rnh = ch->tables[kidx]; 487b074b7bbSAlexander V. Chernikov else 488b074b7bbSAlexander V. Chernikov rnh = ch->xtables[kidx]; 489b074b7bbSAlexander V. Chernikov break; 490b074b7bbSAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 491b074b7bbSAlexander V. Chernikov rnh = ch->xtables[kidx]; 492b074b7bbSAlexander V. Chernikov break; 493b074b7bbSAlexander V. Chernikov } 4943b3a8eb9SGleb Smirnoff 4953b3a8eb9SGleb Smirnoff ent = (struct table_entry *)rnh->rnh_deladdr(sa_ptr, mask_ptr, rnh); 4963b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 4973b3a8eb9SGleb Smirnoff 498b074b7bbSAlexander V. Chernikov IPFW_UH_RUNLOCK(ch); 499b074b7bbSAlexander V. Chernikov 5003b3a8eb9SGleb Smirnoff if (ent == NULL) 5013b3a8eb9SGleb Smirnoff return (ESRCH); 5023b3a8eb9SGleb Smirnoff 5033b3a8eb9SGleb Smirnoff free(ent, M_IPFW_TBL); 5043b3a8eb9SGleb Smirnoff return (0); 5053b3a8eb9SGleb Smirnoff } 5063b3a8eb9SGleb Smirnoff 5073b3a8eb9SGleb Smirnoff static int 5083b3a8eb9SGleb Smirnoff flush_table_entry(struct radix_node *rn, void *arg) 5093b3a8eb9SGleb Smirnoff { 5103b3a8eb9SGleb Smirnoff struct radix_node_head * const rnh = arg; 5113b3a8eb9SGleb Smirnoff struct table_entry *ent; 5123b3a8eb9SGleb Smirnoff 5133b3a8eb9SGleb Smirnoff ent = (struct table_entry *) 5143b3a8eb9SGleb Smirnoff rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 5153b3a8eb9SGleb Smirnoff if (ent != NULL) 5163b3a8eb9SGleb Smirnoff free(ent, M_IPFW_TBL); 5173b3a8eb9SGleb Smirnoff return (0); 5183b3a8eb9SGleb Smirnoff } 5193b3a8eb9SGleb Smirnoff 520b074b7bbSAlexander V. Chernikov /* 521b074b7bbSAlexander V. Chernikov * Flushes all entries in given table minimizing hoding chain WLOCKs. 522b074b7bbSAlexander V. Chernikov * 523b074b7bbSAlexander V. Chernikov */ 5243b3a8eb9SGleb Smirnoff int 525b074b7bbSAlexander V. Chernikov ipfw_flush_table(struct ip_fw_chain *ch, struct tid_info *ti) 5263b3a8eb9SGleb Smirnoff { 527b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 528b074b7bbSAlexander V. Chernikov struct table_config *tc; 529b074b7bbSAlexander V. Chernikov void *ostate, *oxstate; 530b074b7bbSAlexander V. Chernikov void *state, *xstate; 531b074b7bbSAlexander V. Chernikov int error; 532b074b7bbSAlexander V. Chernikov uint8_t type; 533b074b7bbSAlexander V. Chernikov uint16_t kidx; 5343b3a8eb9SGleb Smirnoff 535b074b7bbSAlexander V. Chernikov if (ti->uidx >= V_fw_tables_max) 5363b3a8eb9SGleb Smirnoff return (EINVAL); 5373b3a8eb9SGleb Smirnoff 5383b3a8eb9SGleb Smirnoff /* 539b074b7bbSAlexander V. Chernikov * Stage 1: determine table type. 540b074b7bbSAlexander V. Chernikov * Reference found table to ensure it won't disappear. 5413b3a8eb9SGleb Smirnoff */ 542b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 543b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 544b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 545b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 546b074b7bbSAlexander V. Chernikov return (ESRCH); 547b074b7bbSAlexander V. Chernikov } 548b074b7bbSAlexander V. Chernikov type = tc->no.type; 549b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 550b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 5513b3a8eb9SGleb Smirnoff 552b074b7bbSAlexander V. Chernikov /* 553b074b7bbSAlexander V. Chernikov * Stage 2: allocate new state for given type. 554b074b7bbSAlexander V. Chernikov */ 555b074b7bbSAlexander V. Chernikov if ((error = alloc_table_state(&state, &xstate, type)) != 0) { 556b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 557b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 558b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 559b074b7bbSAlexander V. Chernikov return (error); 560b074b7bbSAlexander V. Chernikov } 561b074b7bbSAlexander V. Chernikov 562b074b7bbSAlexander V. Chernikov /* 563b074b7bbSAlexander V. Chernikov * Stage 3: swap old state pointers with newly-allocated ones. 564b074b7bbSAlexander V. Chernikov * Decrease refcount. 565b074b7bbSAlexander V. Chernikov */ 566b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 5673b3a8eb9SGleb Smirnoff IPFW_WLOCK(ch); 568b074b7bbSAlexander V. Chernikov 569b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 570b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 571b074b7bbSAlexander V. Chernikov 572b074b7bbSAlexander V. Chernikov ostate = ch->tables[kidx]; 573b074b7bbSAlexander V. Chernikov ch->tables[kidx] = state; 574b074b7bbSAlexander V. Chernikov oxstate = ch->xtables[kidx]; 575b074b7bbSAlexander V. Chernikov ch->xtables[kidx] = xstate; 576b074b7bbSAlexander V. Chernikov 577b074b7bbSAlexander V. Chernikov tc->no.refcnt--; 578b074b7bbSAlexander V. Chernikov 5793b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 580b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 5813b3a8eb9SGleb Smirnoff 582b074b7bbSAlexander V. Chernikov /* 583b074b7bbSAlexander V. Chernikov * Stage 4: perform real flush. 584b074b7bbSAlexander V. Chernikov */ 585b074b7bbSAlexander V. Chernikov free_table_state(&ostate, &xstate, tc->no.type); 5863b3a8eb9SGleb Smirnoff 5873b3a8eb9SGleb Smirnoff return (0); 5883b3a8eb9SGleb Smirnoff } 5893b3a8eb9SGleb Smirnoff 590b074b7bbSAlexander V. Chernikov /* 591b074b7bbSAlexander V. Chernikov * Destroys given table @ti: flushes it, 592b074b7bbSAlexander V. Chernikov */ 593b074b7bbSAlexander V. Chernikov int 594b074b7bbSAlexander V. Chernikov ipfw_destroy_table(struct ip_fw_chain *ch, struct tid_info *ti, int force) 595b074b7bbSAlexander V. Chernikov { 596b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 597b074b7bbSAlexander V. Chernikov struct table_config *tc; 598b074b7bbSAlexander V. Chernikov 599b074b7bbSAlexander V. Chernikov ti->set = TABLE_SET(ti->set); 600b074b7bbSAlexander V. Chernikov 601b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 602b074b7bbSAlexander V. Chernikov 603b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 604b074b7bbSAlexander V. Chernikov if ((tc = find_table(ni, ti)) == NULL) { 605b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 606b074b7bbSAlexander V. Chernikov return (ESRCH); 607b074b7bbSAlexander V. Chernikov } 608b074b7bbSAlexander V. Chernikov 609b074b7bbSAlexander V. Chernikov /* Do not permit destroying used tables */ 610b074b7bbSAlexander V. Chernikov if (tc->no.refcnt > 0 && force == 0) { 611b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 612b074b7bbSAlexander V. Chernikov return (EBUSY); 613b074b7bbSAlexander V. Chernikov } 614b074b7bbSAlexander V. Chernikov 615b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 616b074b7bbSAlexander V. Chernikov unlink_table(ch, tc); 617b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 618b074b7bbSAlexander V. Chernikov 619b074b7bbSAlexander V. Chernikov /* Free obj index */ 620b074b7bbSAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, tc->no.set, tc->no.kidx) != 0) 621b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 622b074b7bbSAlexander V. Chernikov tc->no.kidx, tc->tablename); 623b074b7bbSAlexander V. Chernikov 624b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 625b074b7bbSAlexander V. Chernikov 626b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 627b074b7bbSAlexander V. Chernikov 628b074b7bbSAlexander V. Chernikov return (0); 629b074b7bbSAlexander V. Chernikov } 630b074b7bbSAlexander V. Chernikov 631b074b7bbSAlexander V. Chernikov static void 632b074b7bbSAlexander V. Chernikov destroy_table_locked(struct namedobj_instance *ni, struct named_object *no, 633b074b7bbSAlexander V. Chernikov void *arg) 634b074b7bbSAlexander V. Chernikov { 635b074b7bbSAlexander V. Chernikov 636b074b7bbSAlexander V. Chernikov unlink_table((struct ip_fw_chain *)arg, (struct table_config *)no); 637b074b7bbSAlexander V. Chernikov if (ipfw_objhash_free_idx(ni, no->set, no->kidx) != 0) 638b074b7bbSAlexander V. Chernikov printf("Error unlinking kidx %d from table %s\n", 639b074b7bbSAlexander V. Chernikov no->kidx, no->name); 640b074b7bbSAlexander V. Chernikov free_table_config(ni, (struct table_config *)no); 641b074b7bbSAlexander V. Chernikov } 642b074b7bbSAlexander V. Chernikov 6433b3a8eb9SGleb Smirnoff void 6443b3a8eb9SGleb Smirnoff ipfw_destroy_tables(struct ip_fw_chain *ch) 6453b3a8eb9SGleb Smirnoff { 6463b3a8eb9SGleb Smirnoff 647b074b7bbSAlexander V. Chernikov /* Remove all tables from working set */ 648b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(ch); 649b074b7bbSAlexander V. Chernikov IPFW_WLOCK(ch); 650b074b7bbSAlexander V. Chernikov ipfw_objhash_foreach(CHAIN_TO_NI(ch), destroy_table_locked, ch); 651b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 652b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(ch); 6533b3a8eb9SGleb Smirnoff 6543b3a8eb9SGleb Smirnoff /* Free pointers itself */ 6553b3a8eb9SGleb Smirnoff free(ch->tables, M_IPFW); 6563b3a8eb9SGleb Smirnoff free(ch->xtables, M_IPFW); 657b074b7bbSAlexander V. Chernikov 658b074b7bbSAlexander V. Chernikov ipfw_objhash_destroy(CHAIN_TO_NI(ch)); 659b074b7bbSAlexander V. Chernikov free(CHAIN_TO_TCFG(ch), M_IPFW); 6603b3a8eb9SGleb Smirnoff } 6613b3a8eb9SGleb Smirnoff 6623b3a8eb9SGleb Smirnoff int 6633b3a8eb9SGleb Smirnoff ipfw_init_tables(struct ip_fw_chain *ch) 6643b3a8eb9SGleb Smirnoff { 665b074b7bbSAlexander V. Chernikov struct tables_config *tcfg; 666b074b7bbSAlexander V. Chernikov 6673b3a8eb9SGleb Smirnoff /* Allocate pointers */ 6683b3a8eb9SGleb Smirnoff ch->tables = malloc(V_fw_tables_max * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO); 6693b3a8eb9SGleb Smirnoff ch->xtables = malloc(V_fw_tables_max * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO); 670b074b7bbSAlexander V. Chernikov 671b074b7bbSAlexander V. Chernikov tcfg = malloc(sizeof(struct tables_config), M_IPFW, M_WAITOK | M_ZERO); 672b074b7bbSAlexander V. Chernikov tcfg->namehash = ipfw_objhash_create(V_fw_tables_max); 673b074b7bbSAlexander V. Chernikov ch->tblcfg = tcfg; 674b074b7bbSAlexander V. Chernikov 6753b3a8eb9SGleb Smirnoff return (0); 6763b3a8eb9SGleb Smirnoff } 6773b3a8eb9SGleb Smirnoff 6783b3a8eb9SGleb Smirnoff int 6793b3a8eb9SGleb Smirnoff ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) 6803b3a8eb9SGleb Smirnoff { 6813b3a8eb9SGleb Smirnoff struct radix_node_head **tables, **xtables, *rnh; 6823b3a8eb9SGleb Smirnoff struct radix_node_head **tables_old, **xtables_old; 6833b3a8eb9SGleb Smirnoff unsigned int ntables_old, tbl; 684b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 685b074b7bbSAlexander V. Chernikov void *new_idx; 686b074b7bbSAlexander V. Chernikov int new_blocks; 6873b3a8eb9SGleb Smirnoff 6883b3a8eb9SGleb Smirnoff /* Check new value for validity */ 6893b3a8eb9SGleb Smirnoff if (ntables > IPFW_TABLES_MAX) 6903b3a8eb9SGleb Smirnoff ntables = IPFW_TABLES_MAX; 6913b3a8eb9SGleb Smirnoff 6923b3a8eb9SGleb Smirnoff /* Allocate new pointers */ 6933b3a8eb9SGleb Smirnoff tables = malloc(ntables * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO); 6943b3a8eb9SGleb Smirnoff xtables = malloc(ntables * sizeof(void *), M_IPFW, M_WAITOK | M_ZERO); 695b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_alloc(ntables, (void *)&new_idx, &new_blocks); 6963b3a8eb9SGleb Smirnoff 6973b3a8eb9SGleb Smirnoff IPFW_WLOCK(ch); 6983b3a8eb9SGleb Smirnoff 6993b3a8eb9SGleb Smirnoff tbl = (ntables >= V_fw_tables_max) ? V_fw_tables_max : ntables; 700b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(ch); 701b074b7bbSAlexander V. Chernikov 702b074b7bbSAlexander V. Chernikov /* Temportary restrict decreasing max_tables */ 703b074b7bbSAlexander V. Chernikov if (ipfw_objhash_bitmap_merge(ni, &new_idx, &new_blocks) != 0) { 704b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(ch); 705b074b7bbSAlexander V. Chernikov free(tables, M_IPFW); 706b074b7bbSAlexander V. Chernikov free(xtables, M_IPFW); 707b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 708b074b7bbSAlexander V. Chernikov return (EINVAL); 709b074b7bbSAlexander V. Chernikov } 7103b3a8eb9SGleb Smirnoff 7113b3a8eb9SGleb Smirnoff /* Copy old table pointers */ 7123b3a8eb9SGleb Smirnoff memcpy(tables, ch->tables, sizeof(void *) * tbl); 7133b3a8eb9SGleb Smirnoff memcpy(xtables, ch->xtables, sizeof(void *) * tbl); 7143b3a8eb9SGleb Smirnoff 7153b3a8eb9SGleb Smirnoff /* Change pointers and number of tables */ 7163b3a8eb9SGleb Smirnoff tables_old = ch->tables; 7173b3a8eb9SGleb Smirnoff xtables_old = ch->xtables; 7183b3a8eb9SGleb Smirnoff ch->tables = tables; 7193b3a8eb9SGleb Smirnoff ch->xtables = xtables; 7203b3a8eb9SGleb Smirnoff 7213b3a8eb9SGleb Smirnoff ntables_old = V_fw_tables_max; 7223b3a8eb9SGleb Smirnoff V_fw_tables_max = ntables; 7233b3a8eb9SGleb Smirnoff 7243b3a8eb9SGleb Smirnoff IPFW_WUNLOCK(ch); 7253b3a8eb9SGleb Smirnoff 7263b3a8eb9SGleb Smirnoff /* Check if we need to destroy radix trees */ 7273b3a8eb9SGleb Smirnoff if (ntables < ntables_old) { 7283b3a8eb9SGleb Smirnoff for (tbl = ntables; tbl < ntables_old; tbl++) { 7293b3a8eb9SGleb Smirnoff if ((rnh = tables_old[tbl]) != NULL) { 7303b3a8eb9SGleb Smirnoff rnh->rnh_walktree(rnh, flush_table_entry, rnh); 7313b3a8eb9SGleb Smirnoff rn_detachhead((void **)&rnh); 7323b3a8eb9SGleb Smirnoff } 7333b3a8eb9SGleb Smirnoff 7343b3a8eb9SGleb Smirnoff if ((rnh = xtables_old[tbl]) != NULL) { 7353b3a8eb9SGleb Smirnoff rnh->rnh_walktree(rnh, flush_table_entry, rnh); 7363b3a8eb9SGleb Smirnoff rn_detachhead((void **)&rnh); 7373b3a8eb9SGleb Smirnoff } 7383b3a8eb9SGleb Smirnoff } 7393b3a8eb9SGleb Smirnoff } 7403b3a8eb9SGleb Smirnoff 7413b3a8eb9SGleb Smirnoff /* Free old pointers */ 7423b3a8eb9SGleb Smirnoff free(tables_old, M_IPFW); 7433b3a8eb9SGleb Smirnoff free(xtables_old, M_IPFW); 744b074b7bbSAlexander V. Chernikov ipfw_objhash_bitmap_free(new_idx, new_blocks); 7453b3a8eb9SGleb Smirnoff 7463b3a8eb9SGleb Smirnoff return (0); 7473b3a8eb9SGleb Smirnoff } 7483b3a8eb9SGleb Smirnoff 7493b3a8eb9SGleb Smirnoff int 7503b3a8eb9SGleb Smirnoff ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 7513b3a8eb9SGleb Smirnoff uint32_t *val) 7523b3a8eb9SGleb Smirnoff { 7533b3a8eb9SGleb Smirnoff struct radix_node_head *rnh; 7543b3a8eb9SGleb Smirnoff struct table_entry *ent; 7553b3a8eb9SGleb Smirnoff struct sockaddr_in sa; 7563b3a8eb9SGleb Smirnoff 7573b3a8eb9SGleb Smirnoff if (tbl >= V_fw_tables_max) 7583b3a8eb9SGleb Smirnoff return (0); 7593b3a8eb9SGleb Smirnoff if ((rnh = ch->tables[tbl]) == NULL) 7603b3a8eb9SGleb Smirnoff return (0); 7613b3a8eb9SGleb Smirnoff KEY_LEN(sa) = KEY_LEN_INET; 7623b3a8eb9SGleb Smirnoff sa.sin_addr.s_addr = addr; 763d28d2aa4SAlexander V. Chernikov ent = (struct table_entry *)(rnh->rnh_matchaddr(&sa, rnh)); 7643b3a8eb9SGleb Smirnoff if (ent != NULL) { 7653b3a8eb9SGleb Smirnoff *val = ent->value; 7663b3a8eb9SGleb Smirnoff return (1); 7673b3a8eb9SGleb Smirnoff } 7683b3a8eb9SGleb Smirnoff return (0); 7693b3a8eb9SGleb Smirnoff } 7703b3a8eb9SGleb Smirnoff 7713b3a8eb9SGleb Smirnoff int 7723b3a8eb9SGleb Smirnoff ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr, 7733b3a8eb9SGleb Smirnoff uint32_t *val, int type) 7743b3a8eb9SGleb Smirnoff { 7753b3a8eb9SGleb Smirnoff struct radix_node_head *rnh; 7763b3a8eb9SGleb Smirnoff struct table_xentry *xent; 7773b3a8eb9SGleb Smirnoff struct sockaddr_in6 sa6; 7783b3a8eb9SGleb Smirnoff struct xaddr_iface iface; 7793b3a8eb9SGleb Smirnoff 7803b3a8eb9SGleb Smirnoff if (tbl >= V_fw_tables_max) 7813b3a8eb9SGleb Smirnoff return (0); 7823b3a8eb9SGleb Smirnoff if ((rnh = ch->xtables[tbl]) == NULL) 7833b3a8eb9SGleb Smirnoff return (0); 7843b3a8eb9SGleb Smirnoff 7853b3a8eb9SGleb Smirnoff switch (type) { 7863b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 7873b3a8eb9SGleb Smirnoff KEY_LEN(sa6) = KEY_LEN_INET6; 7883b3a8eb9SGleb Smirnoff memcpy(&sa6.sin6_addr, paddr, sizeof(struct in6_addr)); 789d28d2aa4SAlexander V. Chernikov xent = (struct table_xentry *)(rnh->rnh_matchaddr(&sa6, rnh)); 7903b3a8eb9SGleb Smirnoff break; 7913b3a8eb9SGleb Smirnoff 7923b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 7933b3a8eb9SGleb Smirnoff KEY_LEN(iface) = KEY_LEN_IFACE + 7943b3a8eb9SGleb Smirnoff strlcpy(iface.ifname, (char *)paddr, IF_NAMESIZE) + 1; 7953b3a8eb9SGleb Smirnoff /* Assume direct match */ 7963b3a8eb9SGleb Smirnoff /* FIXME: Add interface pattern matching */ 797d28d2aa4SAlexander V. Chernikov xent = (struct table_xentry *)(rnh->rnh_matchaddr(&iface, rnh)); 7983b3a8eb9SGleb Smirnoff break; 7993b3a8eb9SGleb Smirnoff 8003b3a8eb9SGleb Smirnoff default: 8013b3a8eb9SGleb Smirnoff return (0); 8023b3a8eb9SGleb Smirnoff } 8033b3a8eb9SGleb Smirnoff 8043b3a8eb9SGleb Smirnoff if (xent != NULL) { 8053b3a8eb9SGleb Smirnoff *val = xent->value; 8063b3a8eb9SGleb Smirnoff return (1); 8073b3a8eb9SGleb Smirnoff } 8083b3a8eb9SGleb Smirnoff return (0); 8093b3a8eb9SGleb Smirnoff } 8103b3a8eb9SGleb Smirnoff 8113b3a8eb9SGleb Smirnoff static int 8123b3a8eb9SGleb Smirnoff count_table_entry(struct radix_node *rn, void *arg) 8133b3a8eb9SGleb Smirnoff { 8143b3a8eb9SGleb Smirnoff u_int32_t * const cnt = arg; 8153b3a8eb9SGleb Smirnoff 8163b3a8eb9SGleb Smirnoff (*cnt)++; 8173b3a8eb9SGleb Smirnoff return (0); 8183b3a8eb9SGleb Smirnoff } 8193b3a8eb9SGleb Smirnoff 8203b3a8eb9SGleb Smirnoff int 821b074b7bbSAlexander V. Chernikov ipfw_count_table(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 8223b3a8eb9SGleb Smirnoff { 8233b3a8eb9SGleb Smirnoff struct radix_node_head *rnh; 824b074b7bbSAlexander V. Chernikov struct table_config *tc; 8253b3a8eb9SGleb Smirnoff 826b074b7bbSAlexander V. Chernikov if (ti->uidx >= V_fw_tables_max) 8273b3a8eb9SGleb Smirnoff return (EINVAL); 828b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 829b074b7bbSAlexander V. Chernikov return (ESRCH); 8303b3a8eb9SGleb Smirnoff *cnt = 0; 831b074b7bbSAlexander V. Chernikov if ((rnh = ch->tables[tc->no.kidx]) == NULL) 8323b3a8eb9SGleb Smirnoff return (0); 8333b3a8eb9SGleb Smirnoff rnh->rnh_walktree(rnh, count_table_entry, cnt); 8343b3a8eb9SGleb Smirnoff return (0); 8353b3a8eb9SGleb Smirnoff } 8363b3a8eb9SGleb Smirnoff 8373b3a8eb9SGleb Smirnoff static int 8383b3a8eb9SGleb Smirnoff dump_table_entry(struct radix_node *rn, void *arg) 8393b3a8eb9SGleb Smirnoff { 8403b3a8eb9SGleb Smirnoff struct table_entry * const n = (struct table_entry *)rn; 8413b3a8eb9SGleb Smirnoff ipfw_table * const tbl = arg; 8423b3a8eb9SGleb Smirnoff ipfw_table_entry *ent; 8433b3a8eb9SGleb Smirnoff 8443b3a8eb9SGleb Smirnoff if (tbl->cnt == tbl->size) 8453b3a8eb9SGleb Smirnoff return (1); 8463b3a8eb9SGleb Smirnoff ent = &tbl->ent[tbl->cnt]; 8473b3a8eb9SGleb Smirnoff ent->tbl = tbl->tbl; 8483b3a8eb9SGleb Smirnoff if (in_nullhost(n->mask.sin_addr)) 8493b3a8eb9SGleb Smirnoff ent->masklen = 0; 8503b3a8eb9SGleb Smirnoff else 8513b3a8eb9SGleb Smirnoff ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr)); 8523b3a8eb9SGleb Smirnoff ent->addr = n->addr.sin_addr.s_addr; 8533b3a8eb9SGleb Smirnoff ent->value = n->value; 8543b3a8eb9SGleb Smirnoff tbl->cnt++; 8553b3a8eb9SGleb Smirnoff return (0); 8563b3a8eb9SGleb Smirnoff } 8573b3a8eb9SGleb Smirnoff 8583b3a8eb9SGleb Smirnoff int 859b074b7bbSAlexander V. Chernikov ipfw_dump_table(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_table *tbl) 8603b3a8eb9SGleb Smirnoff { 8613b3a8eb9SGleb Smirnoff struct radix_node_head *rnh; 862b074b7bbSAlexander V. Chernikov struct table_config *tc; 8633b3a8eb9SGleb Smirnoff 864b074b7bbSAlexander V. Chernikov if (ti->uidx >= V_fw_tables_max) 8653b3a8eb9SGleb Smirnoff return (EINVAL); 866b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 867b074b7bbSAlexander V. Chernikov return (ESRCH); 8683b3a8eb9SGleb Smirnoff tbl->cnt = 0; 869b074b7bbSAlexander V. Chernikov if ((rnh = ch->tables[tc->no.kidx]) == NULL) 8703b3a8eb9SGleb Smirnoff return (0); 8713b3a8eb9SGleb Smirnoff rnh->rnh_walktree(rnh, dump_table_entry, tbl); 8723b3a8eb9SGleb Smirnoff return (0); 8733b3a8eb9SGleb Smirnoff } 8743b3a8eb9SGleb Smirnoff 8753b3a8eb9SGleb Smirnoff static int 8763b3a8eb9SGleb Smirnoff count_table_xentry(struct radix_node *rn, void *arg) 8773b3a8eb9SGleb Smirnoff { 8783b3a8eb9SGleb Smirnoff uint32_t * const cnt = arg; 8793b3a8eb9SGleb Smirnoff 8803b3a8eb9SGleb Smirnoff (*cnt) += sizeof(ipfw_table_xentry); 8813b3a8eb9SGleb Smirnoff return (0); 8823b3a8eb9SGleb Smirnoff } 8833b3a8eb9SGleb Smirnoff 8843b3a8eb9SGleb Smirnoff int 885b074b7bbSAlexander V. Chernikov ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) 8863b3a8eb9SGleb Smirnoff { 8873b3a8eb9SGleb Smirnoff struct radix_node_head *rnh; 888b074b7bbSAlexander V. Chernikov struct table_config *tc; 8893b3a8eb9SGleb Smirnoff 890b074b7bbSAlexander V. Chernikov if (ti->uidx >= V_fw_tables_max) 8913b3a8eb9SGleb Smirnoff return (EINVAL); 8923b3a8eb9SGleb Smirnoff *cnt = 0; 893b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 894b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 895b074b7bbSAlexander V. Chernikov if ((rnh = ch->tables[tc->no.kidx]) != NULL) 8963b3a8eb9SGleb Smirnoff rnh->rnh_walktree(rnh, count_table_xentry, cnt); 897b074b7bbSAlexander V. Chernikov if ((rnh = ch->xtables[tc->no.kidx]) != NULL) 8983b3a8eb9SGleb Smirnoff rnh->rnh_walktree(rnh, count_table_xentry, cnt); 8993b3a8eb9SGleb Smirnoff /* Return zero if table is empty */ 9003b3a8eb9SGleb Smirnoff if (*cnt > 0) 9013b3a8eb9SGleb Smirnoff (*cnt) += sizeof(ipfw_xtable); 9023b3a8eb9SGleb Smirnoff return (0); 9033b3a8eb9SGleb Smirnoff } 9043b3a8eb9SGleb Smirnoff 9053b3a8eb9SGleb Smirnoff 9063b3a8eb9SGleb Smirnoff static int 9073b3a8eb9SGleb Smirnoff dump_table_xentry_base(struct radix_node *rn, void *arg) 9083b3a8eb9SGleb Smirnoff { 9093b3a8eb9SGleb Smirnoff struct table_entry * const n = (struct table_entry *)rn; 9103b3a8eb9SGleb Smirnoff ipfw_xtable * const tbl = arg; 9113b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 9123b3a8eb9SGleb Smirnoff 9133b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 9143b3a8eb9SGleb Smirnoff if (tbl->cnt == tbl->size) 9153b3a8eb9SGleb Smirnoff return (1); 9163b3a8eb9SGleb Smirnoff xent = &tbl->xent[tbl->cnt]; 9173b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 9183b3a8eb9SGleb Smirnoff xent->tbl = tbl->tbl; 9193b3a8eb9SGleb Smirnoff if (in_nullhost(n->mask.sin_addr)) 9203b3a8eb9SGleb Smirnoff xent->masklen = 0; 9213b3a8eb9SGleb Smirnoff else 9223b3a8eb9SGleb Smirnoff xent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr)); 9233b3a8eb9SGleb Smirnoff /* Save IPv4 address as deprecated IPv6 compatible */ 9243b3a8eb9SGleb Smirnoff xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr; 925c3015737SAlexander V. Chernikov xent->flags = IPFW_TCF_INET; 9263b3a8eb9SGleb Smirnoff xent->value = n->value; 9273b3a8eb9SGleb Smirnoff tbl->cnt++; 9283b3a8eb9SGleb Smirnoff return (0); 9293b3a8eb9SGleb Smirnoff } 9303b3a8eb9SGleb Smirnoff 9313b3a8eb9SGleb Smirnoff static int 9323b3a8eb9SGleb Smirnoff dump_table_xentry_extended(struct radix_node *rn, void *arg) 9333b3a8eb9SGleb Smirnoff { 9343b3a8eb9SGleb Smirnoff struct table_xentry * const n = (struct table_xentry *)rn; 9353b3a8eb9SGleb Smirnoff ipfw_xtable * const tbl = arg; 9363b3a8eb9SGleb Smirnoff ipfw_table_xentry *xent; 9373b3a8eb9SGleb Smirnoff #ifdef INET6 9383b3a8eb9SGleb Smirnoff int i; 9393b3a8eb9SGleb Smirnoff uint32_t *v; 9403b3a8eb9SGleb Smirnoff #endif 9413b3a8eb9SGleb Smirnoff /* Out of memory, returning */ 9423b3a8eb9SGleb Smirnoff if (tbl->cnt == tbl->size) 9433b3a8eb9SGleb Smirnoff return (1); 9443b3a8eb9SGleb Smirnoff xent = &tbl->xent[tbl->cnt]; 9453b3a8eb9SGleb Smirnoff xent->len = sizeof(ipfw_table_xentry); 9463b3a8eb9SGleb Smirnoff xent->tbl = tbl->tbl; 9473b3a8eb9SGleb Smirnoff 9483b3a8eb9SGleb Smirnoff switch (tbl->type) { 9493b3a8eb9SGleb Smirnoff #ifdef INET6 9503b3a8eb9SGleb Smirnoff case IPFW_TABLE_CIDR: 9513b3a8eb9SGleb Smirnoff /* Count IPv6 mask */ 9523b3a8eb9SGleb Smirnoff v = (uint32_t *)&n->m.mask6.sin6_addr; 9533b3a8eb9SGleb Smirnoff for (i = 0; i < sizeof(struct in6_addr) / 4; i++, v++) 9543b3a8eb9SGleb Smirnoff xent->masklen += bitcount32(*v); 9553b3a8eb9SGleb Smirnoff memcpy(&xent->k, &n->a.addr6.sin6_addr, sizeof(struct in6_addr)); 9563b3a8eb9SGleb Smirnoff break; 9573b3a8eb9SGleb Smirnoff #endif 9583b3a8eb9SGleb Smirnoff case IPFW_TABLE_INTERFACE: 9593b3a8eb9SGleb Smirnoff /* Assume exact mask */ 9603b3a8eb9SGleb Smirnoff xent->masklen = 8 * IF_NAMESIZE; 9613b3a8eb9SGleb Smirnoff memcpy(&xent->k, &n->a.iface.ifname, IF_NAMESIZE); 9623b3a8eb9SGleb Smirnoff break; 9633b3a8eb9SGleb Smirnoff 9643b3a8eb9SGleb Smirnoff default: 9653b3a8eb9SGleb Smirnoff /* unknown, skip entry */ 9663b3a8eb9SGleb Smirnoff return (0); 9673b3a8eb9SGleb Smirnoff } 9683b3a8eb9SGleb Smirnoff 9693b3a8eb9SGleb Smirnoff xent->value = n->value; 9703b3a8eb9SGleb Smirnoff tbl->cnt++; 9713b3a8eb9SGleb Smirnoff return (0); 9723b3a8eb9SGleb Smirnoff } 9733b3a8eb9SGleb Smirnoff 9743b3a8eb9SGleb Smirnoff int 975b074b7bbSAlexander V. Chernikov ipfw_dump_xtable(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_xtable *tbl) 9763b3a8eb9SGleb Smirnoff { 9773b3a8eb9SGleb Smirnoff struct radix_node_head *rnh; 978b074b7bbSAlexander V. Chernikov struct table_config *tc; 9793b3a8eb9SGleb Smirnoff 9803b3a8eb9SGleb Smirnoff if (tbl->tbl >= V_fw_tables_max) 9813b3a8eb9SGleb Smirnoff return (EINVAL); 9823b3a8eb9SGleb Smirnoff tbl->cnt = 0; 983b074b7bbSAlexander V. Chernikov 984b074b7bbSAlexander V. Chernikov if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) 985b074b7bbSAlexander V. Chernikov return (0); /* XXX: We should return ESRCH */ 986b074b7bbSAlexander V. Chernikov tbl->type = tc->no.type; 987b074b7bbSAlexander V. Chernikov if ((rnh = ch->tables[tc->no.kidx]) != NULL) 9883b3a8eb9SGleb Smirnoff rnh->rnh_walktree(rnh, dump_table_xentry_base, tbl); 989b074b7bbSAlexander V. Chernikov if ((rnh = ch->xtables[tc->no.kidx]) != NULL) 9903b3a8eb9SGleb Smirnoff rnh->rnh_walktree(rnh, dump_table_xentry_extended, tbl); 9913b3a8eb9SGleb Smirnoff return (0); 9923b3a8eb9SGleb Smirnoff } 9933b3a8eb9SGleb Smirnoff 994b074b7bbSAlexander V. Chernikov /* 995b074b7bbSAlexander V. Chernikov * Tables rewriting code 996b074b7bbSAlexander V. Chernikov * 997b074b7bbSAlexander V. Chernikov */ 998b074b7bbSAlexander V. Chernikov 999b074b7bbSAlexander V. Chernikov /* 1000b074b7bbSAlexander V. Chernikov * Determine table number and lookup type for @cmd. 1001b074b7bbSAlexander V. Chernikov * Fill @tbl and @type with appropriate values. 1002b074b7bbSAlexander V. Chernikov * Returns 0 for relevant opcodes, 1 otherwise. 1003b074b7bbSAlexander V. Chernikov */ 1004b074b7bbSAlexander V. Chernikov static int 1005b074b7bbSAlexander V. Chernikov classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 1006b074b7bbSAlexander V. Chernikov { 1007b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1008b074b7bbSAlexander V. Chernikov int skip; 1009b074b7bbSAlexander V. Chernikov uint16_t v; 1010b074b7bbSAlexander V. Chernikov 1011b074b7bbSAlexander V. Chernikov skip = 1; 1012b074b7bbSAlexander V. Chernikov 1013b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1014b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1015b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1016b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1017b074b7bbSAlexander V. Chernikov *puidx = cmd->arg1; 1018b074b7bbSAlexander V. Chernikov /* Assume CIDR by default */ 1019b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_CIDR; 1020b074b7bbSAlexander V. Chernikov skip = 0; 1021b074b7bbSAlexander V. Chernikov 1022b074b7bbSAlexander V. Chernikov if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { 1023b074b7bbSAlexander V. Chernikov /* 1024b074b7bbSAlexander V. Chernikov * generic lookup. The key must be 1025b074b7bbSAlexander V. Chernikov * in 32bit big-endian format. 1026b074b7bbSAlexander V. Chernikov */ 1027b074b7bbSAlexander V. Chernikov v = ((ipfw_insn_u32 *)cmd)->d[1]; 1028b074b7bbSAlexander V. Chernikov switch (v) { 1029b074b7bbSAlexander V. Chernikov case 0: 1030b074b7bbSAlexander V. Chernikov case 1: 1031b074b7bbSAlexander V. Chernikov /* IPv4 src/dst */ 1032b074b7bbSAlexander V. Chernikov break; 1033b074b7bbSAlexander V. Chernikov case 2: 1034b074b7bbSAlexander V. Chernikov case 3: 1035b074b7bbSAlexander V. Chernikov /* src/dst port */ 1036b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 1037b074b7bbSAlexander V. Chernikov break; 1038b074b7bbSAlexander V. Chernikov case 4: 1039b074b7bbSAlexander V. Chernikov /* uid/gid */ 1040b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 1041b074b7bbSAlexander V. Chernikov case 5: 1042b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U32; 1043b074b7bbSAlexander V. Chernikov /* jid */ 1044b074b7bbSAlexander V. Chernikov case 6: 1045b074b7bbSAlexander V. Chernikov //type = IPFW_TABLE_U16; 1046b074b7bbSAlexander V. Chernikov /* dscp */ 1047b074b7bbSAlexander V. Chernikov break; 1048b074b7bbSAlexander V. Chernikov } 1049b074b7bbSAlexander V. Chernikov } 1050b074b7bbSAlexander V. Chernikov break; 1051b074b7bbSAlexander V. Chernikov case O_XMIT: 1052b074b7bbSAlexander V. Chernikov case O_RECV: 1053b074b7bbSAlexander V. Chernikov case O_VIA: 1054b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1055b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1056b074b7bbSAlexander V. Chernikov if (cmdif->name[0] != '\1') 1057b074b7bbSAlexander V. Chernikov break; 1058b074b7bbSAlexander V. Chernikov 1059b074b7bbSAlexander V. Chernikov *ptype = IPFW_TABLE_INTERFACE; 1060b074b7bbSAlexander V. Chernikov *puidx = cmdif->p.glob; 1061b074b7bbSAlexander V. Chernikov skip = 0; 1062b074b7bbSAlexander V. Chernikov break; 1063b074b7bbSAlexander V. Chernikov } 1064b074b7bbSAlexander V. Chernikov 1065b074b7bbSAlexander V. Chernikov return (skip); 1066b074b7bbSAlexander V. Chernikov } 1067b074b7bbSAlexander V. Chernikov 1068b074b7bbSAlexander V. Chernikov /* 1069b074b7bbSAlexander V. Chernikov * Sets new table value for given opcode. 1070b074b7bbSAlexander V. Chernikov * Assume the same opcodes as classify_table_opcode() 1071b074b7bbSAlexander V. Chernikov */ 1072b074b7bbSAlexander V. Chernikov static void 1073b074b7bbSAlexander V. Chernikov update_table_opcode(ipfw_insn *cmd, uint16_t idx) 1074b074b7bbSAlexander V. Chernikov { 1075b074b7bbSAlexander V. Chernikov ipfw_insn_if *cmdif; 1076b074b7bbSAlexander V. Chernikov 1077b074b7bbSAlexander V. Chernikov switch (cmd->opcode) { 1078b074b7bbSAlexander V. Chernikov case O_IP_SRC_LOOKUP: 1079b074b7bbSAlexander V. Chernikov case O_IP_DST_LOOKUP: 1080b074b7bbSAlexander V. Chernikov /* Basic IPv4/IPv6 or u32 lookups */ 1081b074b7bbSAlexander V. Chernikov cmd->arg1 = idx; 1082b074b7bbSAlexander V. Chernikov break; 1083b074b7bbSAlexander V. Chernikov case O_XMIT: 1084b074b7bbSAlexander V. Chernikov case O_RECV: 1085b074b7bbSAlexander V. Chernikov case O_VIA: 1086b074b7bbSAlexander V. Chernikov /* Interface table, possibly */ 1087b074b7bbSAlexander V. Chernikov cmdif = (ipfw_insn_if *)cmd; 1088b074b7bbSAlexander V. Chernikov cmdif->p.glob = idx; 1089b074b7bbSAlexander V. Chernikov break; 1090b074b7bbSAlexander V. Chernikov } 1091b074b7bbSAlexander V. Chernikov } 1092b074b7bbSAlexander V. Chernikov 1093b074b7bbSAlexander V. Chernikov static char * 1094b074b7bbSAlexander V. Chernikov find_name_tlv(void *tlvs, int len, uint16_t uidx) 1095b074b7bbSAlexander V. Chernikov { 1096b074b7bbSAlexander V. Chernikov ipfw_xtable_ntlv *ntlv; 1097b074b7bbSAlexander V. Chernikov uintptr_t pa, pe; 1098b074b7bbSAlexander V. Chernikov int l; 1099b074b7bbSAlexander V. Chernikov 1100b074b7bbSAlexander V. Chernikov pa = (uintptr_t)tlvs; 1101b074b7bbSAlexander V. Chernikov pe = pa + len; 1102b074b7bbSAlexander V. Chernikov l = 0; 1103b074b7bbSAlexander V. Chernikov for (; pa < pe; pa += l) { 1104b074b7bbSAlexander V. Chernikov ntlv = (ipfw_xtable_ntlv *)pa; 1105b074b7bbSAlexander V. Chernikov l = ntlv->head.length; 1106b074b7bbSAlexander V. Chernikov if (ntlv->head.type != IPFW_TLV_NAME) 1107b074b7bbSAlexander V. Chernikov continue; 1108b074b7bbSAlexander V. Chernikov if (ntlv->idx != uidx) 1109b074b7bbSAlexander V. Chernikov continue; 1110b074b7bbSAlexander V. Chernikov 1111b074b7bbSAlexander V. Chernikov return (ntlv->name); 1112b074b7bbSAlexander V. Chernikov } 1113b074b7bbSAlexander V. Chernikov 1114b074b7bbSAlexander V. Chernikov return (NULL); 1115b074b7bbSAlexander V. Chernikov } 1116b074b7bbSAlexander V. Chernikov 1117b074b7bbSAlexander V. Chernikov static struct table_config * 1118b074b7bbSAlexander V. Chernikov find_table(struct namedobj_instance *ni, struct tid_info *ti) 1119b074b7bbSAlexander V. Chernikov { 1120b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1121b074b7bbSAlexander V. Chernikov struct named_object *no; 1122b074b7bbSAlexander V. Chernikov 1123b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1124b074b7bbSAlexander V. Chernikov name = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1125b074b7bbSAlexander V. Chernikov if (name == NULL) 1126b074b7bbSAlexander V. Chernikov return (NULL); 1127b074b7bbSAlexander V. Chernikov } else { 1128b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1129b074b7bbSAlexander V. Chernikov name = bname; 1130b074b7bbSAlexander V. Chernikov } 1131b074b7bbSAlexander V. Chernikov 1132b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_name(ni, ti->set, name); 1133b074b7bbSAlexander V. Chernikov 1134b074b7bbSAlexander V. Chernikov return ((struct table_config *)no); 1135b074b7bbSAlexander V. Chernikov } 1136b074b7bbSAlexander V. Chernikov 1137b074b7bbSAlexander V. Chernikov static int 1138b074b7bbSAlexander V. Chernikov alloc_table_state(void **state, void **xstate, uint8_t type) 1139b074b7bbSAlexander V. Chernikov { 1140b074b7bbSAlexander V. Chernikov 1141b074b7bbSAlexander V. Chernikov switch (type) { 1142b074b7bbSAlexander V. Chernikov case IPFW_TABLE_CIDR: 1143b074b7bbSAlexander V. Chernikov if (!rn_inithead(state, OFF_LEN_INET)) 1144b074b7bbSAlexander V. Chernikov return (ENOMEM); 1145b074b7bbSAlexander V. Chernikov if (!rn_inithead(xstate, OFF_LEN_INET6)) { 1146b074b7bbSAlexander V. Chernikov rn_detachhead(state); 1147b074b7bbSAlexander V. Chernikov return (ENOMEM); 1148b074b7bbSAlexander V. Chernikov } 1149b074b7bbSAlexander V. Chernikov break; 1150b074b7bbSAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1151b074b7bbSAlexander V. Chernikov *state = NULL; 1152b074b7bbSAlexander V. Chernikov if (!rn_inithead(xstate, OFF_LEN_IFACE)) 1153b074b7bbSAlexander V. Chernikov return (ENOMEM); 1154b074b7bbSAlexander V. Chernikov break; 1155b074b7bbSAlexander V. Chernikov } 1156b074b7bbSAlexander V. Chernikov 1157b074b7bbSAlexander V. Chernikov return (0); 1158b074b7bbSAlexander V. Chernikov } 1159b074b7bbSAlexander V. Chernikov 1160b074b7bbSAlexander V. Chernikov 1161b074b7bbSAlexander V. Chernikov static struct table_config * 1162b074b7bbSAlexander V. Chernikov alloc_table_config(struct namedobj_instance *ni, struct tid_info *ti) 1163b074b7bbSAlexander V. Chernikov { 1164b074b7bbSAlexander V. Chernikov char *name, bname[16]; 1165b074b7bbSAlexander V. Chernikov struct table_config *tc; 1166b074b7bbSAlexander V. Chernikov int error; 1167b074b7bbSAlexander V. Chernikov 1168b074b7bbSAlexander V. Chernikov if (ti->tlvs != NULL) { 1169b074b7bbSAlexander V. Chernikov name = find_name_tlv(ti->tlvs, ti->tlen, ti->uidx); 1170b074b7bbSAlexander V. Chernikov if (name == NULL) 1171b074b7bbSAlexander V. Chernikov return (NULL); 1172b074b7bbSAlexander V. Chernikov } else { 1173b074b7bbSAlexander V. Chernikov snprintf(bname, sizeof(bname), "%d", ti->uidx); 1174b074b7bbSAlexander V. Chernikov name = bname; 1175b074b7bbSAlexander V. Chernikov } 1176b074b7bbSAlexander V. Chernikov 1177b074b7bbSAlexander V. Chernikov tc = malloc(sizeof(struct table_config), M_IPFW, M_WAITOK | M_ZERO); 1178b074b7bbSAlexander V. Chernikov tc->no.name = tc->tablename; 1179b074b7bbSAlexander V. Chernikov tc->no.type = ti->type; 1180b074b7bbSAlexander V. Chernikov tc->no.set = ti->set; 1181b074b7bbSAlexander V. Chernikov strlcpy(tc->tablename, name, sizeof(tc->tablename)); 1182b074b7bbSAlexander V. Chernikov 1183b074b7bbSAlexander V. Chernikov if (ti->tlvs == NULL) { 1184b074b7bbSAlexander V. Chernikov tc->no.compat = 1; 1185b074b7bbSAlexander V. Chernikov tc->no.uidx = ti->uidx; 1186b074b7bbSAlexander V. Chernikov } 1187b074b7bbSAlexander V. Chernikov 1188b074b7bbSAlexander V. Chernikov /* Preallocate data structures for new tables */ 1189b074b7bbSAlexander V. Chernikov error = alloc_table_state(&tc->state, &tc->xstate, ti->type); 1190b074b7bbSAlexander V. Chernikov if (error != 0) { 1191b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1192b074b7bbSAlexander V. Chernikov return (NULL); 1193b074b7bbSAlexander V. Chernikov } 1194b074b7bbSAlexander V. Chernikov 1195b074b7bbSAlexander V. Chernikov return (tc); 1196b074b7bbSAlexander V. Chernikov } 1197b074b7bbSAlexander V. Chernikov 1198b074b7bbSAlexander V. Chernikov static void 1199b074b7bbSAlexander V. Chernikov free_table_state(void **state, void **xstate, uint8_t type) 1200b074b7bbSAlexander V. Chernikov { 1201b074b7bbSAlexander V. Chernikov struct radix_node_head *rnh; 1202b074b7bbSAlexander V. Chernikov 1203b074b7bbSAlexander V. Chernikov switch (type) { 1204b074b7bbSAlexander V. Chernikov case IPFW_TABLE_CIDR: 1205b074b7bbSAlexander V. Chernikov rnh = (struct radix_node_head *)(*state); 1206b074b7bbSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_table_entry, rnh); 1207b074b7bbSAlexander V. Chernikov rn_detachhead(state); 1208b074b7bbSAlexander V. Chernikov 1209b074b7bbSAlexander V. Chernikov rnh = (struct radix_node_head *)(*xstate); 1210b074b7bbSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_table_entry, rnh); 1211b074b7bbSAlexander V. Chernikov rn_detachhead(xstate); 1212b074b7bbSAlexander V. Chernikov break; 1213b074b7bbSAlexander V. Chernikov case IPFW_TABLE_INTERFACE: 1214b074b7bbSAlexander V. Chernikov rnh = (struct radix_node_head *)(*xstate); 1215b074b7bbSAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_table_entry, rnh); 1216b074b7bbSAlexander V. Chernikov rn_detachhead(xstate); 1217b074b7bbSAlexander V. Chernikov break; 1218b074b7bbSAlexander V. Chernikov } 1219b074b7bbSAlexander V. Chernikov } 1220b074b7bbSAlexander V. Chernikov 1221b074b7bbSAlexander V. Chernikov static void 1222b074b7bbSAlexander V. Chernikov free_table_config(struct namedobj_instance *ni, struct table_config *tc) 1223b074b7bbSAlexander V. Chernikov { 1224b074b7bbSAlexander V. Chernikov 1225b074b7bbSAlexander V. Chernikov if (tc->linked == 0) 1226b074b7bbSAlexander V. Chernikov free_table_state(&tc->state, &tc->xstate, tc->no.type); 1227b074b7bbSAlexander V. Chernikov 1228b074b7bbSAlexander V. Chernikov free(tc, M_IPFW); 1229b074b7bbSAlexander V. Chernikov } 1230b074b7bbSAlexander V. Chernikov 1231b074b7bbSAlexander V. Chernikov /* 1232b074b7bbSAlexander V. Chernikov * Links @tc to @chain table named instance. 1233b074b7bbSAlexander V. Chernikov * Sets appropriate type/states in @chain table info. 1234b074b7bbSAlexander V. Chernikov */ 1235b074b7bbSAlexander V. Chernikov static void 1236b074b7bbSAlexander V. Chernikov link_table(struct ip_fw_chain *chain, struct table_config *tc) 1237b074b7bbSAlexander V. Chernikov { 1238b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1239b074b7bbSAlexander V. Chernikov uint16_t kidx; 1240b074b7bbSAlexander V. Chernikov 1241b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(chain); 1242b074b7bbSAlexander V. Chernikov IPFW_WLOCK_ASSERT(chain); 1243b074b7bbSAlexander V. Chernikov 1244b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1245b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1246b074b7bbSAlexander V. Chernikov 1247b074b7bbSAlexander V. Chernikov ipfw_objhash_add(ni, &tc->no); 1248b074b7bbSAlexander V. Chernikov chain->tables[kidx] = tc->state; 1249b074b7bbSAlexander V. Chernikov chain->xtables[kidx] = tc->xstate; 1250b074b7bbSAlexander V. Chernikov 1251b074b7bbSAlexander V. Chernikov tc->linked = 1; 1252b074b7bbSAlexander V. Chernikov } 1253b074b7bbSAlexander V. Chernikov 1254b074b7bbSAlexander V. Chernikov /* 1255b074b7bbSAlexander V. Chernikov * Unlinks @tc from @chain table named instance. 1256b074b7bbSAlexander V. Chernikov * Zeroes states in @chain and stores them in @tc. 1257b074b7bbSAlexander V. Chernikov */ 1258b074b7bbSAlexander V. Chernikov static void 1259b074b7bbSAlexander V. Chernikov unlink_table(struct ip_fw_chain *chain, struct table_config *tc) 1260b074b7bbSAlexander V. Chernikov { 1261b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1262b074b7bbSAlexander V. Chernikov uint16_t kidx; 1263b074b7bbSAlexander V. Chernikov 1264b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK_ASSERT(chain); 1265b074b7bbSAlexander V. Chernikov IPFW_WLOCK_ASSERT(chain); 1266b074b7bbSAlexander V. Chernikov 1267b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1268b074b7bbSAlexander V. Chernikov kidx = tc->no.kidx; 1269b074b7bbSAlexander V. Chernikov 1270b074b7bbSAlexander V. Chernikov /* Clear state and save pointers for flush */ 1271b074b7bbSAlexander V. Chernikov ipfw_objhash_del(ni, &tc->no); 1272b074b7bbSAlexander V. Chernikov tc->state = chain->tables[kidx]; 1273b074b7bbSAlexander V. Chernikov chain->tables[kidx] = NULL; 1274b074b7bbSAlexander V. Chernikov tc->xstate = chain->xtables[kidx]; 1275b074b7bbSAlexander V. Chernikov chain->xtables[kidx] = NULL; 1276b074b7bbSAlexander V. Chernikov 1277b074b7bbSAlexander V. Chernikov tc->linked = 0; 1278b074b7bbSAlexander V. Chernikov } 1279b074b7bbSAlexander V. Chernikov 1280b074b7bbSAlexander V. Chernikov /* 1281b074b7bbSAlexander V. Chernikov * Finds named object by @uidx number. 1282b074b7bbSAlexander V. Chernikov * Refs found object, allocate new index for non-existing object. 1283b074b7bbSAlexander V. Chernikov * Fills in @pidx with userland/kernel indexes. 1284b074b7bbSAlexander V. Chernikov * 1285b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1286b074b7bbSAlexander V. Chernikov */ 1287b074b7bbSAlexander V. Chernikov static int 1288b074b7bbSAlexander V. Chernikov bind_table(struct namedobj_instance *ni, struct rule_check_info *ci, 1289b074b7bbSAlexander V. Chernikov struct obj_idx *pidx, struct tid_info *ti) 1290b074b7bbSAlexander V. Chernikov { 1291b074b7bbSAlexander V. Chernikov struct table_config *tc; 1292b074b7bbSAlexander V. Chernikov 1293b074b7bbSAlexander V. Chernikov tc = find_table(ni, ti); 1294b074b7bbSAlexander V. Chernikov 1295b074b7bbSAlexander V. Chernikov pidx->uidx = ti->uidx; 1296b074b7bbSAlexander V. Chernikov pidx->type = ti->type; 1297b074b7bbSAlexander V. Chernikov 1298b074b7bbSAlexander V. Chernikov if (tc == NULL) { 1299b074b7bbSAlexander V. Chernikov /* Try to acquire refcount */ 1300b074b7bbSAlexander V. Chernikov if (ipfw_objhash_alloc_idx(ni, ti->set, &pidx->kidx) != 0) { 1301b074b7bbSAlexander V. Chernikov printf("Unable to allocate table index in set %u." 1302b074b7bbSAlexander V. Chernikov " Consider increasing net.inet.ip.fw.tables_max", 1303b074b7bbSAlexander V. Chernikov ti->set); 1304b074b7bbSAlexander V. Chernikov return (EBUSY); 1305b074b7bbSAlexander V. Chernikov } 1306b074b7bbSAlexander V. Chernikov 1307b074b7bbSAlexander V. Chernikov pidx->new = 1; 1308b074b7bbSAlexander V. Chernikov ci->new_tables++; 1309b074b7bbSAlexander V. Chernikov 1310b074b7bbSAlexander V. Chernikov return (0); 1311b074b7bbSAlexander V. Chernikov } 1312b074b7bbSAlexander V. Chernikov 1313b074b7bbSAlexander V. Chernikov /* Check if table type if valid first */ 1314b074b7bbSAlexander V. Chernikov if (tc->no.type != ti->type) 1315b074b7bbSAlexander V. Chernikov return (EINVAL); 1316b074b7bbSAlexander V. Chernikov 1317b074b7bbSAlexander V. Chernikov tc->no.refcnt++; 1318b074b7bbSAlexander V. Chernikov 1319b074b7bbSAlexander V. Chernikov pidx->kidx = tc->no.kidx; 1320b074b7bbSAlexander V. Chernikov 1321b074b7bbSAlexander V. Chernikov return (0); 1322b074b7bbSAlexander V. Chernikov } 1323b074b7bbSAlexander V. Chernikov 1324b074b7bbSAlexander V. Chernikov /* 1325b074b7bbSAlexander V. Chernikov * Compatibility function for old ipfw(8) binaries. 1326b074b7bbSAlexander V. Chernikov * Rewrites table kernel indices with userland ones. 1327b074b7bbSAlexander V. Chernikov * Works for \d+ talbes only (e.g. for tables, converted 1328b074b7bbSAlexander V. Chernikov * from old numbered system calls). 1329b074b7bbSAlexander V. Chernikov * 1330b074b7bbSAlexander V. Chernikov * Returns 0 on success. 1331b074b7bbSAlexander V. Chernikov * Raises error on any other tables. 1332b074b7bbSAlexander V. Chernikov */ 1333b074b7bbSAlexander V. Chernikov int 1334b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule) 1335b074b7bbSAlexander V. Chernikov { 1336b074b7bbSAlexander V. Chernikov int cmdlen, l; 1337b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1338b074b7bbSAlexander V. Chernikov uint32_t set; 1339b074b7bbSAlexander V. Chernikov uint16_t kidx; 1340b074b7bbSAlexander V. Chernikov uint8_t type; 1341b074b7bbSAlexander V. Chernikov struct named_object *no; 1342b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1343b074b7bbSAlexander V. Chernikov 1344b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1345b074b7bbSAlexander V. Chernikov 1346b074b7bbSAlexander V. Chernikov set = TABLE_SET(rule->set); 1347b074b7bbSAlexander V. Chernikov 1348b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1349b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1350b074b7bbSAlexander V. Chernikov cmdlen = 0; 1351b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1352b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1353b074b7bbSAlexander V. Chernikov 1354b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1355b074b7bbSAlexander V. Chernikov continue; 1356b074b7bbSAlexander V. Chernikov 1357b074b7bbSAlexander V. Chernikov if ((no = ipfw_objhash_lookup_idx(ni, set, kidx)) == NULL) 1358b074b7bbSAlexander V. Chernikov return (1); 1359b074b7bbSAlexander V. Chernikov 1360b074b7bbSAlexander V. Chernikov if (no->compat == 0) 1361b074b7bbSAlexander V. Chernikov return (2); 1362b074b7bbSAlexander V. Chernikov 1363b074b7bbSAlexander V. Chernikov update_table_opcode(cmd, no->uidx); 1364b074b7bbSAlexander V. Chernikov } 1365b074b7bbSAlexander V. Chernikov 1366b074b7bbSAlexander V. Chernikov return (0); 1367b074b7bbSAlexander V. Chernikov } 1368b074b7bbSAlexander V. Chernikov 1369b074b7bbSAlexander V. Chernikov 1370b074b7bbSAlexander V. Chernikov /* 1371b074b7bbSAlexander V. Chernikov * Checks is opcode is referencing table of appropriate type. 1372b074b7bbSAlexander V. Chernikov * Adds reference count for found table if true. 1373b074b7bbSAlexander V. Chernikov * Rewrites user-supplied opcode values with kernel ones. 1374b074b7bbSAlexander V. Chernikov * 1375b074b7bbSAlexander V. Chernikov * Returns 0 on success and appropriate error code otherwise. 1376b074b7bbSAlexander V. Chernikov */ 1377b074b7bbSAlexander V. Chernikov int 1378b074b7bbSAlexander V. Chernikov ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, 1379b074b7bbSAlexander V. Chernikov struct rule_check_info *ci) 1380b074b7bbSAlexander V. Chernikov { 1381b074b7bbSAlexander V. Chernikov int cmdlen, error, ftype, l; 1382b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1383b074b7bbSAlexander V. Chernikov uint16_t uidx; 1384b074b7bbSAlexander V. Chernikov uint8_t type; 1385b074b7bbSAlexander V. Chernikov struct table_config *tc; 1386b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1387b074b7bbSAlexander V. Chernikov struct named_object *no, *no_n, *no_tmp; 1388b074b7bbSAlexander V. Chernikov struct obj_idx *pidx, *p, *oib; 1389b074b7bbSAlexander V. Chernikov struct namedobjects_head nh; 1390b074b7bbSAlexander V. Chernikov struct tid_info ti; 1391b074b7bbSAlexander V. Chernikov 1392b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1393b074b7bbSAlexander V. Chernikov 1394b074b7bbSAlexander V. Chernikov /* 1395b074b7bbSAlexander V. Chernikov * Prepare an array for storing opcode indices. 1396b074b7bbSAlexander V. Chernikov * Use stack allocation by default. 1397b074b7bbSAlexander V. Chernikov */ 1398b074b7bbSAlexander V. Chernikov if (ci->table_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 1399b074b7bbSAlexander V. Chernikov /* Stack */ 1400b074b7bbSAlexander V. Chernikov pidx = ci->obuf; 1401b074b7bbSAlexander V. Chernikov } else 1402b074b7bbSAlexander V. Chernikov pidx = malloc(ci->table_opcodes * sizeof(struct obj_idx), 1403b074b7bbSAlexander V. Chernikov M_IPFW, M_WAITOK | M_ZERO); 1404b074b7bbSAlexander V. Chernikov 1405b074b7bbSAlexander V. Chernikov oib = pidx; 1406b074b7bbSAlexander V. Chernikov error = 0; 1407b074b7bbSAlexander V. Chernikov 1408b074b7bbSAlexander V. Chernikov type = 0; 1409b074b7bbSAlexander V. Chernikov ftype = 0; 1410b074b7bbSAlexander V. Chernikov 1411b074b7bbSAlexander V. Chernikov ci->tableset = TABLE_SET(ci->krule->set); 1412b074b7bbSAlexander V. Chernikov 1413b074b7bbSAlexander V. Chernikov memset(&ti, 0, sizeof(ti)); 1414b074b7bbSAlexander V. Chernikov ti.set = ci->tableset; 1415b074b7bbSAlexander V. Chernikov ti.tlvs = ci->tlvs; 1416b074b7bbSAlexander V. Chernikov ti.tlen = ci->tlen; 1417b074b7bbSAlexander V. Chernikov 1418b074b7bbSAlexander V. Chernikov /* 1419b074b7bbSAlexander V. Chernikov * Stage 1: reference existing tables and determine number 1420b074b7bbSAlexander V. Chernikov * of tables we need to allocate 1421b074b7bbSAlexander V. Chernikov */ 1422b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(chain); 1423b074b7bbSAlexander V. Chernikov 1424b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 1425b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 1426b074b7bbSAlexander V. Chernikov cmdlen = 0; 1427b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1428b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1429b074b7bbSAlexander V. Chernikov 1430b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &ti.uidx, &ti.type) != 0) 1431b074b7bbSAlexander V. Chernikov continue; 1432b074b7bbSAlexander V. Chernikov 1433b074b7bbSAlexander V. Chernikov /* 1434b074b7bbSAlexander V. Chernikov * Got table opcode with necessary info. 1435b074b7bbSAlexander V. Chernikov * Try to reference existing tables and allocate 1436b074b7bbSAlexander V. Chernikov * indices for non-existing one while holding write lock. 1437b074b7bbSAlexander V. Chernikov */ 1438b074b7bbSAlexander V. Chernikov if ((error = bind_table(ni, ci, pidx, &ti)) != 0) 1439b074b7bbSAlexander V. Chernikov break; 1440b074b7bbSAlexander V. Chernikov 1441b074b7bbSAlexander V. Chernikov /* 1442b074b7bbSAlexander V. Chernikov * @pidx stores either existing ref'd table id or new one. 1443b074b7bbSAlexander V. Chernikov * Move to next index 1444b074b7bbSAlexander V. Chernikov */ 1445b074b7bbSAlexander V. Chernikov 1446b074b7bbSAlexander V. Chernikov pidx++; 1447b074b7bbSAlexander V. Chernikov } 1448b074b7bbSAlexander V. Chernikov 1449b074b7bbSAlexander V. Chernikov if (error != 0) { 1450b074b7bbSAlexander V. Chernikov /* Unref everything we have already done */ 1451b074b7bbSAlexander V. Chernikov for (p = oib; p < pidx; p++) { 1452b074b7bbSAlexander V. Chernikov if (p->new != 0) { 1453b074b7bbSAlexander V. Chernikov ipfw_objhash_free_idx(ni, ci->tableset,p->kidx); 1454b074b7bbSAlexander V. Chernikov continue; 1455b074b7bbSAlexander V. Chernikov } 1456b074b7bbSAlexander V. Chernikov 1457b074b7bbSAlexander V. Chernikov /* Find & unref by existing idx */ 1458b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_idx(ni, ci->tableset, p->kidx); 1459b074b7bbSAlexander V. Chernikov KASSERT(no!=NULL, ("Ref'd table %d disappeared", 1460b074b7bbSAlexander V. Chernikov p->kidx)); 1461b074b7bbSAlexander V. Chernikov 1462b074b7bbSAlexander V. Chernikov no->refcnt--; 1463b074b7bbSAlexander V. Chernikov } 1464b074b7bbSAlexander V. Chernikov 1465b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1466b074b7bbSAlexander V. Chernikov 1467b074b7bbSAlexander V. Chernikov if (oib != ci->obuf) 1468b074b7bbSAlexander V. Chernikov free(oib, M_IPFW); 1469b074b7bbSAlexander V. Chernikov 1470b074b7bbSAlexander V. Chernikov return (error); 1471b074b7bbSAlexander V. Chernikov } 1472b074b7bbSAlexander V. Chernikov 1473b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1474b074b7bbSAlexander V. Chernikov 1475b074b7bbSAlexander V. Chernikov /* 1476b074b7bbSAlexander V. Chernikov * Stage 2: allocate table configs for every non-existent table 1477b074b7bbSAlexander V. Chernikov */ 1478b074b7bbSAlexander V. Chernikov 1479b074b7bbSAlexander V. Chernikov if (ci->new_tables > 0) { 1480b074b7bbSAlexander V. Chernikov /* Prepare queue to store configs */ 1481b074b7bbSAlexander V. Chernikov TAILQ_INIT(&nh); 1482b074b7bbSAlexander V. Chernikov 1483b074b7bbSAlexander V. Chernikov for (p = oib; p < pidx; p++) { 1484b074b7bbSAlexander V. Chernikov if (p->new == 0) 1485b074b7bbSAlexander V. Chernikov continue; 1486b074b7bbSAlexander V. Chernikov 1487b074b7bbSAlexander V. Chernikov /* TODO: get name from TLV */ 1488b074b7bbSAlexander V. Chernikov ti.uidx = p->uidx; 1489b074b7bbSAlexander V. Chernikov ti.type = p->type; 1490b074b7bbSAlexander V. Chernikov 1491b074b7bbSAlexander V. Chernikov tc = alloc_table_config(ni, &ti); 1492b074b7bbSAlexander V. Chernikov 1493b074b7bbSAlexander V. Chernikov if (tc == NULL) { 1494b074b7bbSAlexander V. Chernikov error = ENOMEM; 1495b074b7bbSAlexander V. Chernikov goto free; 1496b074b7bbSAlexander V. Chernikov } 1497b074b7bbSAlexander V. Chernikov 1498b074b7bbSAlexander V. Chernikov tc->no.kidx = p->kidx; 1499b074b7bbSAlexander V. Chernikov tc->no.refcnt = 1; 1500b074b7bbSAlexander V. Chernikov 1501b074b7bbSAlexander V. Chernikov /* Add to list */ 1502b074b7bbSAlexander V. Chernikov TAILQ_INSERT_TAIL(&nh, &tc->no, nn_next); 1503b074b7bbSAlexander V. Chernikov } 1504b074b7bbSAlexander V. Chernikov 1505b074b7bbSAlexander V. Chernikov /* 1506b074b7bbSAlexander V. Chernikov * Stage 2.1: Check if we're going to create 2 tables 1507b074b7bbSAlexander V. Chernikov * with the same name, but different table types. 1508b074b7bbSAlexander V. Chernikov */ 1509b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no, &nh, nn_next) { 1510b074b7bbSAlexander V. Chernikov TAILQ_FOREACH(no_tmp, &nh, nn_next) { 1511b074b7bbSAlexander V. Chernikov if (strcmp(no->name, no_tmp->name) != 0) 1512b074b7bbSAlexander V. Chernikov continue; 1513b074b7bbSAlexander V. Chernikov if (no->type != no_tmp->type) { 1514b074b7bbSAlexander V. Chernikov error = EINVAL; 1515b074b7bbSAlexander V. Chernikov goto free; 1516b074b7bbSAlexander V. Chernikov } 1517b074b7bbSAlexander V. Chernikov } 1518b074b7bbSAlexander V. Chernikov } 1519b074b7bbSAlexander V. Chernikov 1520b074b7bbSAlexander V. Chernikov /* 1521b074b7bbSAlexander V. Chernikov * Stage 3: link & reference new table configs 1522b074b7bbSAlexander V. Chernikov */ 1523b074b7bbSAlexander V. Chernikov 1524b074b7bbSAlexander V. Chernikov IPFW_UH_WLOCK(chain); 1525b074b7bbSAlexander V. Chernikov 1526b074b7bbSAlexander V. Chernikov /* 1527b074b7bbSAlexander V. Chernikov * Step 3.1: Check if some tables we need to create have been 1528b074b7bbSAlexander V. Chernikov * already created with different table type. 1529b074b7bbSAlexander V. Chernikov */ 1530b074b7bbSAlexander V. Chernikov 1531b074b7bbSAlexander V. Chernikov error = 0; 1532b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1533b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1534b074b7bbSAlexander V. Chernikov if (no_n == NULL) 1535b074b7bbSAlexander V. Chernikov continue; 1536b074b7bbSAlexander V. Chernikov 1537b074b7bbSAlexander V. Chernikov if (no_n->type != no->type) { 1538b074b7bbSAlexander V. Chernikov error = EINVAL; 1539b074b7bbSAlexander V. Chernikov break; 1540b074b7bbSAlexander V. Chernikov } 1541b074b7bbSAlexander V. Chernikov 1542b074b7bbSAlexander V. Chernikov } 1543b074b7bbSAlexander V. Chernikov 1544b074b7bbSAlexander V. Chernikov if (error != 0) { 1545b074b7bbSAlexander V. Chernikov /* 1546b074b7bbSAlexander V. Chernikov * Someone has allocated table with different table type. 1547b074b7bbSAlexander V. Chernikov * We have to rollback everything. 1548b074b7bbSAlexander V. Chernikov */ 1549b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1550b074b7bbSAlexander V. Chernikov 1551b074b7bbSAlexander V. Chernikov goto free; 1552b074b7bbSAlexander V. Chernikov } 1553b074b7bbSAlexander V. Chernikov 1554b074b7bbSAlexander V. Chernikov 1555b074b7bbSAlexander V. Chernikov /* 1556b074b7bbSAlexander V. Chernikov * Finally, attach tables and rewrite rule. 1557b074b7bbSAlexander V. Chernikov * We need to set table type for each new table, 1558b074b7bbSAlexander V. Chernikov * so we have to acquire main WLOCK. 1559b074b7bbSAlexander V. Chernikov */ 1560b074b7bbSAlexander V. Chernikov IPFW_WLOCK(chain); 1561b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) { 1562b074b7bbSAlexander V. Chernikov no_n = ipfw_objhash_lookup_name(ni, no->set, no->name); 1563b074b7bbSAlexander V. Chernikov if (no_n != NULL) { 1564b074b7bbSAlexander V. Chernikov /* Increase refcount for existing table */ 1565b074b7bbSAlexander V. Chernikov no_n->refcnt++; 1566b074b7bbSAlexander V. Chernikov /* Keep oib array in sync: update kindx */ 1567b074b7bbSAlexander V. Chernikov for (p = oib; p < pidx; p++) { 1568b074b7bbSAlexander V. Chernikov if (p->kidx == no->kidx) { 1569b074b7bbSAlexander V. Chernikov p->kidx = no_n->kidx; 1570b074b7bbSAlexander V. Chernikov break; 1571b074b7bbSAlexander V. Chernikov } 1572b074b7bbSAlexander V. Chernikov } 1573b074b7bbSAlexander V. Chernikov 1574b074b7bbSAlexander V. Chernikov continue; 1575b074b7bbSAlexander V. Chernikov } 1576b074b7bbSAlexander V. Chernikov 1577b074b7bbSAlexander V. Chernikov /* New table. Attach to runtime hash */ 1578b074b7bbSAlexander V. Chernikov TAILQ_REMOVE(&nh, no, nn_next); 1579b074b7bbSAlexander V. Chernikov 1580b074b7bbSAlexander V. Chernikov link_table(chain, (struct table_config *)no); 1581b074b7bbSAlexander V. Chernikov } 1582b074b7bbSAlexander V. Chernikov IPFW_WUNLOCK(chain); 1583b074b7bbSAlexander V. Chernikov 1584b074b7bbSAlexander V. Chernikov /* Perform rule rewrite */ 1585b074b7bbSAlexander V. Chernikov l = ci->krule->cmd_len; 1586b074b7bbSAlexander V. Chernikov cmd = ci->krule->cmd; 1587b074b7bbSAlexander V. Chernikov cmdlen = 0; 1588b074b7bbSAlexander V. Chernikov pidx = oib; 1589b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1590b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1591b074b7bbSAlexander V. Chernikov 1592b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &uidx, &type) != 0) 1593b074b7bbSAlexander V. Chernikov continue; 1594b074b7bbSAlexander V. Chernikov update_table_opcode(cmd, pidx->kidx); 1595b074b7bbSAlexander V. Chernikov pidx++; 1596b074b7bbSAlexander V. Chernikov } 1597b074b7bbSAlexander V. Chernikov 1598b074b7bbSAlexander V. Chernikov IPFW_UH_WUNLOCK(chain); 1599b074b7bbSAlexander V. Chernikov } 1600b074b7bbSAlexander V. Chernikov 1601b074b7bbSAlexander V. Chernikov error = 0; 1602b074b7bbSAlexander V. Chernikov 1603b074b7bbSAlexander V. Chernikov /* 1604b074b7bbSAlexander V. Chernikov * Stage 4: free resources 1605b074b7bbSAlexander V. Chernikov */ 1606b074b7bbSAlexander V. Chernikov free: 1607b074b7bbSAlexander V. Chernikov TAILQ_FOREACH_SAFE(no, &nh, nn_next, no_tmp) 1608b074b7bbSAlexander V. Chernikov free_table_config(ni, tc); 1609b074b7bbSAlexander V. Chernikov 1610b074b7bbSAlexander V. Chernikov if (oib != ci->obuf) 1611b074b7bbSAlexander V. Chernikov free(oib, M_IPFW); 1612b074b7bbSAlexander V. Chernikov 1613b074b7bbSAlexander V. Chernikov return (error); 1614b074b7bbSAlexander V. Chernikov } 1615b074b7bbSAlexander V. Chernikov 1616b074b7bbSAlexander V. Chernikov /* 1617b074b7bbSAlexander V. Chernikov * Remove references from every table used in @rule. 1618b074b7bbSAlexander V. Chernikov */ 1619b074b7bbSAlexander V. Chernikov void 1620b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule) 1621b074b7bbSAlexander V. Chernikov { 1622b074b7bbSAlexander V. Chernikov int cmdlen, l; 1623b074b7bbSAlexander V. Chernikov ipfw_insn *cmd; 1624b074b7bbSAlexander V. Chernikov struct namedobj_instance *ni; 1625b074b7bbSAlexander V. Chernikov struct named_object *no; 1626b074b7bbSAlexander V. Chernikov uint32_t set; 1627b074b7bbSAlexander V. Chernikov uint16_t kidx; 1628b074b7bbSAlexander V. Chernikov uint8_t type; 1629b074b7bbSAlexander V. Chernikov 1630b074b7bbSAlexander V. Chernikov ni = CHAIN_TO_NI(chain); 1631b074b7bbSAlexander V. Chernikov 1632b074b7bbSAlexander V. Chernikov set = TABLE_SET(rule->set); 1633b074b7bbSAlexander V. Chernikov 1634b074b7bbSAlexander V. Chernikov l = rule->cmd_len; 1635b074b7bbSAlexander V. Chernikov cmd = rule->cmd; 1636b074b7bbSAlexander V. Chernikov cmdlen = 0; 1637b074b7bbSAlexander V. Chernikov for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1638b074b7bbSAlexander V. Chernikov cmdlen = F_LEN(cmd); 1639b074b7bbSAlexander V. Chernikov 1640b074b7bbSAlexander V. Chernikov if (classify_table_opcode(cmd, &kidx, &type) != 0) 1641b074b7bbSAlexander V. Chernikov continue; 1642b074b7bbSAlexander V. Chernikov 1643b074b7bbSAlexander V. Chernikov no = ipfw_objhash_lookup_idx(ni, set, kidx); 1644b074b7bbSAlexander V. Chernikov 1645b074b7bbSAlexander V. Chernikov KASSERT(no != NULL, ("table id %d not found", kidx)); 1646b074b7bbSAlexander V. Chernikov KASSERT(no->type == type, ("wrong type %d (%d) for table id %d", 1647b074b7bbSAlexander V. Chernikov no->type, type, kidx)); 1648b074b7bbSAlexander V. Chernikov KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 1649b074b7bbSAlexander V. Chernikov kidx, no->refcnt)); 1650b074b7bbSAlexander V. Chernikov 1651b074b7bbSAlexander V. Chernikov no->refcnt--; 1652b074b7bbSAlexander V. Chernikov } 1653b074b7bbSAlexander V. Chernikov } 1654b074b7bbSAlexander V. Chernikov 1655b074b7bbSAlexander V. Chernikov 1656b074b7bbSAlexander V. Chernikov /* 1657b074b7bbSAlexander V. Chernikov * Removes table bindings for every rule in rule chain @head. 1658b074b7bbSAlexander V. Chernikov */ 1659b074b7bbSAlexander V. Chernikov void 1660b074b7bbSAlexander V. Chernikov ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head) 1661b074b7bbSAlexander V. Chernikov { 1662b074b7bbSAlexander V. Chernikov struct ip_fw *rule; 1663b074b7bbSAlexander V. Chernikov 1664b074b7bbSAlexander V. Chernikov while ((rule = head) != NULL) { 1665b074b7bbSAlexander V. Chernikov head = head->x_next; 1666b074b7bbSAlexander V. Chernikov ipfw_unbind_table_rule(chain, rule); 1667b074b7bbSAlexander V. Chernikov } 1668b074b7bbSAlexander V. Chernikov } 1669b074b7bbSAlexander V. Chernikov 1670b074b7bbSAlexander V. Chernikov 16713b3a8eb9SGleb Smirnoff /* end of file */ 1672