19f7d47b0SAlexander V. Chernikov /*- 29f7d47b0SAlexander V. Chernikov * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. 39f7d47b0SAlexander V. Chernikov * 49f7d47b0SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 59f7d47b0SAlexander V. Chernikov * modification, are permitted provided that the following conditions 69f7d47b0SAlexander V. Chernikov * are met: 79f7d47b0SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 89f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 99f7d47b0SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 109f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 119f7d47b0SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 129f7d47b0SAlexander V. Chernikov * 139f7d47b0SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 149f7d47b0SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 159f7d47b0SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 169f7d47b0SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 179f7d47b0SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 189f7d47b0SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 199f7d47b0SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 209f7d47b0SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 219f7d47b0SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 229f7d47b0SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 239f7d47b0SAlexander V. Chernikov * SUCH DAMAGE. 249f7d47b0SAlexander V. Chernikov */ 259f7d47b0SAlexander V. Chernikov 269f7d47b0SAlexander V. Chernikov #include <sys/cdefs.h> 279f7d47b0SAlexander V. Chernikov __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-12 09:59:11Z melifaro $"); 289f7d47b0SAlexander V. Chernikov 299f7d47b0SAlexander V. Chernikov /* 309f7d47b0SAlexander V. Chernikov * Lookup table algorithms. 319f7d47b0SAlexander V. Chernikov * 329f7d47b0SAlexander V. Chernikov */ 339f7d47b0SAlexander V. Chernikov 349f7d47b0SAlexander V. Chernikov #include "opt_ipfw.h" 359f7d47b0SAlexander V. Chernikov #include "opt_inet.h" 369f7d47b0SAlexander V. Chernikov #ifndef INET 379f7d47b0SAlexander V. Chernikov #error IPFIREWALL requires INET. 389f7d47b0SAlexander V. Chernikov #endif /* INET */ 399f7d47b0SAlexander V. Chernikov #include "opt_inet6.h" 409f7d47b0SAlexander V. Chernikov 419f7d47b0SAlexander V. Chernikov #include <sys/param.h> 429f7d47b0SAlexander V. Chernikov #include <sys/systm.h> 439f7d47b0SAlexander V. Chernikov #include <sys/malloc.h> 449f7d47b0SAlexander V. Chernikov #include <sys/kernel.h> 459f7d47b0SAlexander V. Chernikov #include <sys/lock.h> 469f7d47b0SAlexander V. Chernikov #include <sys/rwlock.h> 479f7d47b0SAlexander V. Chernikov #include <sys/socket.h> 489f7d47b0SAlexander V. Chernikov #include <sys/queue.h> 499f7d47b0SAlexander V. Chernikov #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 509f7d47b0SAlexander V. Chernikov #include <net/radix.h> 519f7d47b0SAlexander V. Chernikov #include <net/route.h> 529f7d47b0SAlexander V. Chernikov #include <net/vnet.h> 539f7d47b0SAlexander V. Chernikov 549f7d47b0SAlexander V. Chernikov #include <netinet/in.h> 559f7d47b0SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 569f7d47b0SAlexander V. Chernikov #include <netinet/ip_fw.h> 579f7d47b0SAlexander V. Chernikov 589f7d47b0SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h> 59ea761a5dSAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_table.h> 609f7d47b0SAlexander V. Chernikov 619f7d47b0SAlexander V. Chernikov static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 629f7d47b0SAlexander V. Chernikov 63*68394ec8SAlexander V. Chernikov static int badd(const void *key, void *item, void *base, size_t nmemb, 64*68394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)); 65*68394ec8SAlexander V. Chernikov static int bdel(const void *key, void *base, size_t nmemb, size_t size, 66*68394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)); 67*68394ec8SAlexander V. Chernikov 68*68394ec8SAlexander V. Chernikov 69*68394ec8SAlexander V. Chernikov /* 70*68394ec8SAlexander V. Chernikov * CIDR implementation using radix 71*68394ec8SAlexander V. Chernikov * 72*68394ec8SAlexander V. Chernikov */ 73*68394ec8SAlexander V. Chernikov 749f7d47b0SAlexander V. Chernikov /* 759f7d47b0SAlexander V. Chernikov * The radix code expects addr and mask to be array of bytes, 769f7d47b0SAlexander V. Chernikov * with the first byte being the length of the array. rn_inithead 779f7d47b0SAlexander V. Chernikov * is called with the offset in bits of the lookup key within the 789f7d47b0SAlexander V. Chernikov * array. If we use a sockaddr_in as the underlying type, 799f7d47b0SAlexander V. Chernikov * sin_len is conveniently located at offset 0, sin_addr is at 809f7d47b0SAlexander V. Chernikov * offset 4 and normally aligned. 819f7d47b0SAlexander V. Chernikov * But for portability, let's avoid assumption and make the code explicit 829f7d47b0SAlexander V. Chernikov */ 839f7d47b0SAlexander V. Chernikov #define KEY_LEN(v) *((uint8_t *)&(v)) 849f7d47b0SAlexander V. Chernikov /* 859f7d47b0SAlexander V. Chernikov * Do not require radix to compare more than actual IPv4/IPv6 address 869f7d47b0SAlexander V. Chernikov */ 879f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t)) 88e0a8b9eeSAlexander V. Chernikov #define KEY_LEN_INET6 (offsetof(struct sa_in6, sin6_addr) + sizeof(struct in6_addr)) 899f7d47b0SAlexander V. Chernikov 909f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr)) 91e0a8b9eeSAlexander V. Chernikov #define OFF_LEN_INET6 (8 * offsetof(struct sa_in6, sin6_addr)) 929f7d47b0SAlexander V. Chernikov 93e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry { 949f7d47b0SAlexander V. Chernikov struct radix_node rn[2]; 95e0a8b9eeSAlexander V. Chernikov struct sockaddr_in addr; 96e0a8b9eeSAlexander V. Chernikov uint32_t value; 97e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 98e0a8b9eeSAlexander V. Chernikov }; 99e0a8b9eeSAlexander V. Chernikov 100e0a8b9eeSAlexander V. Chernikov struct sa_in6 { 101e0a8b9eeSAlexander V. Chernikov uint8_t sin6_len; 102e0a8b9eeSAlexander V. Chernikov uint8_t sin6_family; 103e0a8b9eeSAlexander V. Chernikov uint8_t pad[2]; 104e0a8b9eeSAlexander V. Chernikov struct in6_addr sin6_addr; 105e0a8b9eeSAlexander V. Chernikov }; 106e0a8b9eeSAlexander V. Chernikov 107e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry { 108e0a8b9eeSAlexander V. Chernikov struct radix_node rn[2]; 109e0a8b9eeSAlexander V. Chernikov struct sa_in6 addr6; 110e0a8b9eeSAlexander V. Chernikov uint32_t value; 111e0a8b9eeSAlexander V. Chernikov uint8_t masklen; 1129f7d47b0SAlexander V. Chernikov }; 1139f7d47b0SAlexander V. Chernikov 1149f7d47b0SAlexander V. Chernikov static int 1159f7d47b0SAlexander V. Chernikov ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 1169f7d47b0SAlexander V. Chernikov uint32_t *val) 1179f7d47b0SAlexander V. Chernikov { 1189f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 1199f7d47b0SAlexander V. Chernikov 1209f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 121e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 1229f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 1239f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 1249f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 1259f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 126e0a8b9eeSAlexander V. Chernikov ent = (struct radix_cidr_entry *)(rnh->rnh_matchaddr(&sa, rnh)); 1279f7d47b0SAlexander V. Chernikov if (ent != NULL) { 1289f7d47b0SAlexander V. Chernikov *val = ent->value; 1299f7d47b0SAlexander V. Chernikov return (1); 1309f7d47b0SAlexander V. Chernikov } 1319f7d47b0SAlexander V. Chernikov } else { 132e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xent; 133e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 1349f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 1359f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 1369f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 137e0a8b9eeSAlexander V. Chernikov xent = (struct radix_cidr_xentry *)(rnh->rnh_matchaddr(&sa6, rnh)); 1389f7d47b0SAlexander V. Chernikov if (xent != NULL) { 1399f7d47b0SAlexander V. Chernikov *val = xent->value; 1409f7d47b0SAlexander V. Chernikov return (1); 1419f7d47b0SAlexander V. Chernikov } 1429f7d47b0SAlexander V. Chernikov } 1439f7d47b0SAlexander V. Chernikov 1449f7d47b0SAlexander V. Chernikov return (0); 1459f7d47b0SAlexander V. Chernikov } 1469f7d47b0SAlexander V. Chernikov 1479f7d47b0SAlexander V. Chernikov /* 1489f7d47b0SAlexander V. Chernikov * New table 1499f7d47b0SAlexander V. Chernikov */ 1509f7d47b0SAlexander V. Chernikov static int 151*68394ec8SAlexander V. Chernikov ta_init_radix(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 152*68394ec8SAlexander V. Chernikov char *data) 1539f7d47b0SAlexander V. Chernikov { 1549f7d47b0SAlexander V. Chernikov 1559f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET)) 1569f7d47b0SAlexander V. Chernikov return (ENOMEM); 1579f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) { 1589f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 1599f7d47b0SAlexander V. Chernikov return (ENOMEM); 1609f7d47b0SAlexander V. Chernikov } 1619f7d47b0SAlexander V. Chernikov 1629f7d47b0SAlexander V. Chernikov *ta_state = NULL; 1639f7d47b0SAlexander V. Chernikov ti->lookup = ta_lookup_radix; 1649f7d47b0SAlexander V. Chernikov 1659f7d47b0SAlexander V. Chernikov return (0); 1669f7d47b0SAlexander V. Chernikov } 1679f7d47b0SAlexander V. Chernikov 1689f7d47b0SAlexander V. Chernikov static int 1699f7d47b0SAlexander V. Chernikov flush_table_entry(struct radix_node *rn, void *arg) 1709f7d47b0SAlexander V. Chernikov { 1719f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 172e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 1739f7d47b0SAlexander V. Chernikov 174e0a8b9eeSAlexander V. Chernikov ent = (struct radix_cidr_entry *) 1759f7d47b0SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 1769f7d47b0SAlexander V. Chernikov if (ent != NULL) 1779f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 1789f7d47b0SAlexander V. Chernikov return (0); 1799f7d47b0SAlexander V. Chernikov } 1809f7d47b0SAlexander V. Chernikov 1819f7d47b0SAlexander V. Chernikov static void 1829f7d47b0SAlexander V. Chernikov ta_destroy_radix(void *ta_state, struct table_info *ti) 1839f7d47b0SAlexander V. Chernikov { 1849f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 1859f7d47b0SAlexander V. Chernikov 1869f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 1879f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_table_entry, rnh); 1889f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 1899f7d47b0SAlexander V. Chernikov 1909f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 1919f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_table_entry, rnh); 1929f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate); 1939f7d47b0SAlexander V. Chernikov } 1949f7d47b0SAlexander V. Chernikov 1959f7d47b0SAlexander V. Chernikov static int 19681d3153dSAlexander V. Chernikov ta_dump_radix_tentry(void *ta_state, struct table_info *ti, void *e, 19781d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 1989f7d47b0SAlexander V. Chernikov { 199e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *n; 200e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xn; 2019f7d47b0SAlexander V. Chernikov 202e0a8b9eeSAlexander V. Chernikov n = (struct radix_cidr_entry *)e; 2039f7d47b0SAlexander V. Chernikov 2049f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 2059f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) { 20681d3153dSAlexander V. Chernikov tent->k.addr.s_addr = n->addr.sin_addr.s_addr; 207e0a8b9eeSAlexander V. Chernikov tent->masklen = n->masklen; 20881d3153dSAlexander V. Chernikov tent->subtype = AF_INET; 20981d3153dSAlexander V. Chernikov tent->value = n->value; 2109f7d47b0SAlexander V. Chernikov #ifdef INET6 2119f7d47b0SAlexander V. Chernikov } else { 212e0a8b9eeSAlexander V. Chernikov xn = (struct radix_cidr_xentry *)e; 213e0a8b9eeSAlexander V. Chernikov memcpy(&tent->k, &xn->addr6.sin6_addr, sizeof(struct in6_addr)); 214e0a8b9eeSAlexander V. Chernikov tent->masklen = xn->masklen; 21581d3153dSAlexander V. Chernikov tent->subtype = AF_INET6; 21681d3153dSAlexander V. Chernikov tent->value = xn->value; 2179f7d47b0SAlexander V. Chernikov #endif 2189f7d47b0SAlexander V. Chernikov } 2199f7d47b0SAlexander V. Chernikov 2209f7d47b0SAlexander V. Chernikov return (0); 2219f7d47b0SAlexander V. Chernikov } 2229f7d47b0SAlexander V. Chernikov 22381d3153dSAlexander V. Chernikov static int 22481d3153dSAlexander V. Chernikov ta_find_radix_tentry(void *ta_state, struct table_info *ti, void *key, 22581d3153dSAlexander V. Chernikov uint32_t keylen, ipfw_obj_tentry *tent) 22681d3153dSAlexander V. Chernikov { 22781d3153dSAlexander V. Chernikov struct radix_node_head *rnh; 22881d3153dSAlexander V. Chernikov void *e; 22981d3153dSAlexander V. Chernikov 23081d3153dSAlexander V. Chernikov e = NULL; 23181d3153dSAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 23281d3153dSAlexander V. Chernikov struct sockaddr_in sa; 23381d3153dSAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 23481d3153dSAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 23581d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 23681d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa, rnh); 23781d3153dSAlexander V. Chernikov } else { 238e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6; 23981d3153dSAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 24081d3153dSAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 24181d3153dSAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 24281d3153dSAlexander V. Chernikov e = rnh->rnh_matchaddr(&sa6, rnh); 24381d3153dSAlexander V. Chernikov } 24481d3153dSAlexander V. Chernikov 24581d3153dSAlexander V. Chernikov if (e != NULL) { 24681d3153dSAlexander V. Chernikov ta_dump_radix_tentry(ta_state, ti, e, tent); 24781d3153dSAlexander V. Chernikov return (0); 24881d3153dSAlexander V. Chernikov } 24981d3153dSAlexander V. Chernikov 25081d3153dSAlexander V. Chernikov return (ENOENT); 25181d3153dSAlexander V. Chernikov } 25281d3153dSAlexander V. Chernikov 2539f7d47b0SAlexander V. Chernikov static void 2549f7d47b0SAlexander V. Chernikov ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 2559f7d47b0SAlexander V. Chernikov void *arg) 2569f7d47b0SAlexander V. Chernikov { 2579f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 2589f7d47b0SAlexander V. Chernikov 2599f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 2609f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 2619f7d47b0SAlexander V. Chernikov 2629f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 2639f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 2649f7d47b0SAlexander V. Chernikov } 2659f7d47b0SAlexander V. Chernikov 2669f7d47b0SAlexander V. Chernikov 2679f7d47b0SAlexander V. Chernikov struct ta_buf_cidr 2689f7d47b0SAlexander V. Chernikov { 2699f7d47b0SAlexander V. Chernikov struct sockaddr *addr_ptr; 2709f7d47b0SAlexander V. Chernikov struct sockaddr *mask_ptr; 2719f7d47b0SAlexander V. Chernikov void *ent_ptr; 2729f7d47b0SAlexander V. Chernikov union { 2739f7d47b0SAlexander V. Chernikov struct { 2749f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 2759f7d47b0SAlexander V. Chernikov struct sockaddr_in ma; 2769f7d47b0SAlexander V. Chernikov } a4; 2779f7d47b0SAlexander V. Chernikov struct { 278e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa; 279e0a8b9eeSAlexander V. Chernikov struct sa_in6 ma; 2809f7d47b0SAlexander V. Chernikov } a6; 2819f7d47b0SAlexander V. Chernikov } addr; 2829f7d47b0SAlexander V. Chernikov }; 2839f7d47b0SAlexander V. Chernikov 2849f7d47b0SAlexander V. Chernikov #ifdef INET6 2859f7d47b0SAlexander V. Chernikov static inline void 2869f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 2879f7d47b0SAlexander V. Chernikov { 2889f7d47b0SAlexander V. Chernikov uint32_t *cp; 2899f7d47b0SAlexander V. Chernikov 2909f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 2919f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 2929f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 2939f7d47b0SAlexander V. Chernikov } 2949f7d47b0SAlexander V. Chernikov #endif 2959f7d47b0SAlexander V. Chernikov 2969f7d47b0SAlexander V. Chernikov 2979f7d47b0SAlexander V. Chernikov static int 298*68394ec8SAlexander V. Chernikov ta_prepare_add_cidr(struct ip_fw_chain *ch, struct tentry_info *tei, 299*68394ec8SAlexander V. Chernikov void *ta_buf) 3009f7d47b0SAlexander V. Chernikov { 3019f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 302e0a8b9eeSAlexander V. Chernikov struct radix_cidr_entry *ent; 303e0a8b9eeSAlexander V. Chernikov struct radix_cidr_xentry *xent; 3049f7d47b0SAlexander V. Chernikov in_addr_t addr; 305e0a8b9eeSAlexander V. Chernikov struct sockaddr_in *mask; 306e0a8b9eeSAlexander V. Chernikov struct sa_in6 *mask6; 3079f7d47b0SAlexander V. Chernikov int mlen; 3089f7d47b0SAlexander V. Chernikov 3099f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 3109f7d47b0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 3119f7d47b0SAlexander V. Chernikov 3129f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 3139f7d47b0SAlexander V. Chernikov 314ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 3159f7d47b0SAlexander V. Chernikov #ifdef INET 3169f7d47b0SAlexander V. Chernikov if (mlen > 32) 3179f7d47b0SAlexander V. Chernikov return (EINVAL); 3189f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 3199f7d47b0SAlexander V. Chernikov ent->value = tei->value; 320e0a8b9eeSAlexander V. Chernikov mask = &tb->addr.a4.ma; 3219f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 3229f7d47b0SAlexander V. Chernikov KEY_LEN(ent->addr) = KEY_LEN_INET; 323e0a8b9eeSAlexander V. Chernikov KEY_LEN(*mask) = KEY_LEN_INET; 3249f7d47b0SAlexander V. Chernikov ent->addr.sin_family = AF_INET; 325e0a8b9eeSAlexander V. Chernikov mask->sin_addr.s_addr = 3269f7d47b0SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 3279f7d47b0SAlexander V. Chernikov addr = *((in_addr_t *)tei->paddr); 328e0a8b9eeSAlexander V. Chernikov ent->addr.sin_addr.s_addr = addr & mask->sin_addr.s_addr; 329e0a8b9eeSAlexander V. Chernikov ent->masklen = mlen; 3309f7d47b0SAlexander V. Chernikov /* Set pointers */ 3319f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent; 3329f7d47b0SAlexander V. Chernikov tb->addr_ptr = (struct sockaddr *)&ent->addr; 333e0a8b9eeSAlexander V. Chernikov if (mlen != 32) 334e0a8b9eeSAlexander V. Chernikov tb->mask_ptr = (struct sockaddr *)mask; 3359f7d47b0SAlexander V. Chernikov #endif 3369f7d47b0SAlexander V. Chernikov #ifdef INET6 337ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 3389f7d47b0SAlexander V. Chernikov /* IPv6 case */ 3399f7d47b0SAlexander V. Chernikov if (mlen > 128) 3409f7d47b0SAlexander V. Chernikov return (EINVAL); 3419f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 3429f7d47b0SAlexander V. Chernikov xent->value = tei->value; 343e0a8b9eeSAlexander V. Chernikov mask6 = &tb->addr.a6.ma; 3449f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 345e0a8b9eeSAlexander V. Chernikov KEY_LEN(xent->addr6) = KEY_LEN_INET6; 346e0a8b9eeSAlexander V. Chernikov KEY_LEN(*mask6) = KEY_LEN_INET6; 347e0a8b9eeSAlexander V. Chernikov xent->addr6.sin6_family = AF_INET6; 348e0a8b9eeSAlexander V. Chernikov ipv6_writemask(&mask6->sin6_addr, mlen); 349e0a8b9eeSAlexander V. Chernikov memcpy(&xent->addr6.sin6_addr, tei->paddr, 3509f7d47b0SAlexander V. Chernikov sizeof(struct in6_addr)); 351e0a8b9eeSAlexander V. Chernikov APPLY_MASK(&xent->addr6.sin6_addr, &mask6->sin6_addr); 352e0a8b9eeSAlexander V. Chernikov xent->masklen = mlen; 3539f7d47b0SAlexander V. Chernikov /* Set pointers */ 3549f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 355e0a8b9eeSAlexander V. Chernikov tb->addr_ptr = (struct sockaddr *)&xent->addr6; 356e0a8b9eeSAlexander V. Chernikov if (mlen != 128) 357e0a8b9eeSAlexander V. Chernikov tb->mask_ptr = (struct sockaddr *)mask6; 3589f7d47b0SAlexander V. Chernikov #endif 3599f7d47b0SAlexander V. Chernikov } else { 3609f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */ 3619f7d47b0SAlexander V. Chernikov return (EINVAL); 3629f7d47b0SAlexander V. Chernikov } 3639f7d47b0SAlexander V. Chernikov 3649f7d47b0SAlexander V. Chernikov return (0); 3659f7d47b0SAlexander V. Chernikov } 3669f7d47b0SAlexander V. Chernikov 3679f7d47b0SAlexander V. Chernikov static int 3689f7d47b0SAlexander V. Chernikov ta_add_cidr(void *ta_state, struct table_info *ti, 369db785d31SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint64_t *pflags) 3709f7d47b0SAlexander V. Chernikov { 3719f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 3729f7d47b0SAlexander V. Chernikov struct radix_node *rn; 3739f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 374ac35ff17SAlexander V. Chernikov uint32_t value; 3759f7d47b0SAlexander V. Chernikov 3769f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 3779f7d47b0SAlexander V. Chernikov 378ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 3799f7d47b0SAlexander V. Chernikov rnh = ti->state; 3809f7d47b0SAlexander V. Chernikov else 3819f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 3829f7d47b0SAlexander V. Chernikov 3839f7d47b0SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr); 3849f7d47b0SAlexander V. Chernikov 385ac35ff17SAlexander V. Chernikov if (rn == NULL) { 386ac35ff17SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 3879f7d47b0SAlexander V. Chernikov return (EEXIST); 388ac35ff17SAlexander V. Chernikov /* Record already exists. Update value if we're asked to */ 389ac35ff17SAlexander V. Chernikov rn = rnh->rnh_lookup(tb->addr_ptr, tb->mask_ptr, rnh); 390ac35ff17SAlexander V. Chernikov if (rn == NULL) { 391ac35ff17SAlexander V. Chernikov 392ac35ff17SAlexander V. Chernikov /* 393ac35ff17SAlexander V. Chernikov * Radix may have failed addition for other reasons 394ac35ff17SAlexander V. Chernikov * like failure in mask allocation code. 395ac35ff17SAlexander V. Chernikov */ 396ac35ff17SAlexander V. Chernikov return (EINVAL); 397ac35ff17SAlexander V. Chernikov } 398ac35ff17SAlexander V. Chernikov 399ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 400ac35ff17SAlexander V. Chernikov /* IPv4. */ 401e0a8b9eeSAlexander V. Chernikov value = ((struct radix_cidr_entry *)tb->ent_ptr)->value; 402e0a8b9eeSAlexander V. Chernikov ((struct radix_cidr_entry *)rn)->value = value; 403ac35ff17SAlexander V. Chernikov } else { 404ac35ff17SAlexander V. Chernikov /* IPv6 */ 405e0a8b9eeSAlexander V. Chernikov value = ((struct radix_cidr_xentry *)tb->ent_ptr)->value; 406e0a8b9eeSAlexander V. Chernikov ((struct radix_cidr_xentry *)rn)->value = value; 407ac35ff17SAlexander V. Chernikov } 408ac35ff17SAlexander V. Chernikov 409ac35ff17SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 410ac35ff17SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 411e0a8b9eeSAlexander V. Chernikov 412e0a8b9eeSAlexander V. Chernikov return (0); 413ac35ff17SAlexander V. Chernikov } 414ac35ff17SAlexander V. Chernikov 415ac35ff17SAlexander V. Chernikov tb->ent_ptr = NULL; 4169f7d47b0SAlexander V. Chernikov 4179f7d47b0SAlexander V. Chernikov return (0); 4189f7d47b0SAlexander V. Chernikov } 4199f7d47b0SAlexander V. Chernikov 4209f7d47b0SAlexander V. Chernikov static int 421*68394ec8SAlexander V. Chernikov ta_prepare_del_cidr(struct ip_fw_chain *ch, struct tentry_info *tei, 422*68394ec8SAlexander V. Chernikov void *ta_buf) 4239f7d47b0SAlexander V. Chernikov { 4249f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 425e0a8b9eeSAlexander V. Chernikov struct sockaddr_in sa, mask; 426e0a8b9eeSAlexander V. Chernikov struct sa_in6 sa6, mask6; 4279f7d47b0SAlexander V. Chernikov in_addr_t addr; 4289f7d47b0SAlexander V. Chernikov int mlen; 4299f7d47b0SAlexander V. Chernikov 4309f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 4319f7d47b0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 4329f7d47b0SAlexander V. Chernikov 4339f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 4349f7d47b0SAlexander V. Chernikov 435ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) { 436e0a8b9eeSAlexander V. Chernikov if (mlen > 32) 437e0a8b9eeSAlexander V. Chernikov return (EINVAL); 438e0a8b9eeSAlexander V. Chernikov memset(&sa, 0, sizeof(struct sockaddr_in)); 439e0a8b9eeSAlexander V. Chernikov memset(&mask, 0, sizeof(struct sockaddr_in)); 4409f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 4419f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 4429f7d47b0SAlexander V. Chernikov KEY_LEN(mask) = KEY_LEN_INET; 4439f7d47b0SAlexander V. Chernikov mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 4449f7d47b0SAlexander V. Chernikov addr = *((in_addr_t *)tei->paddr); 4459f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 4469f7d47b0SAlexander V. Chernikov tb->addr.a4.sa = sa; 4479f7d47b0SAlexander V. Chernikov tb->addr.a4.ma = mask; 4489f7d47b0SAlexander V. Chernikov tb->addr_ptr = (struct sockaddr *)&tb->addr.a4.sa; 449e0a8b9eeSAlexander V. Chernikov if (mlen != 32) 4509f7d47b0SAlexander V. Chernikov tb->mask_ptr = (struct sockaddr *)&tb->addr.a4.ma; 4519f7d47b0SAlexander V. Chernikov #ifdef INET6 452ac35ff17SAlexander V. Chernikov } else if (tei->subtype == AF_INET6) { 4539f7d47b0SAlexander V. Chernikov if (mlen > 128) 4549f7d47b0SAlexander V. Chernikov return (EINVAL); 455e0a8b9eeSAlexander V. Chernikov memset(&sa6, 0, sizeof(struct sa_in6)); 456e0a8b9eeSAlexander V. Chernikov memset(&mask6, 0, sizeof(struct sa_in6)); 4579f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 4589f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 4599f7d47b0SAlexander V. Chernikov KEY_LEN(mask6) = KEY_LEN_INET6; 4609f7d47b0SAlexander V. Chernikov ipv6_writemask(&mask6.sin6_addr, mlen); 4619f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, tei->paddr, 4629f7d47b0SAlexander V. Chernikov sizeof(struct in6_addr)); 4639f7d47b0SAlexander V. Chernikov APPLY_MASK(&sa6.sin6_addr, &mask6.sin6_addr); 4649f7d47b0SAlexander V. Chernikov tb->addr.a6.sa = sa6; 4659f7d47b0SAlexander V. Chernikov tb->addr.a6.ma = mask6; 4669f7d47b0SAlexander V. Chernikov tb->addr_ptr = (struct sockaddr *)&tb->addr.a6.sa; 467e0a8b9eeSAlexander V. Chernikov if (mlen != 128) 4689f7d47b0SAlexander V. Chernikov tb->mask_ptr = (struct sockaddr *)&tb->addr.a6.ma; 4699f7d47b0SAlexander V. Chernikov #endif 4709f7d47b0SAlexander V. Chernikov } else 4719f7d47b0SAlexander V. Chernikov return (EINVAL); 4729f7d47b0SAlexander V. Chernikov 4739f7d47b0SAlexander V. Chernikov return (0); 4749f7d47b0SAlexander V. Chernikov } 4759f7d47b0SAlexander V. Chernikov 4769f7d47b0SAlexander V. Chernikov static int 4779f7d47b0SAlexander V. Chernikov ta_del_cidr(void *ta_state, struct table_info *ti, 478db785d31SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint64_t *pflags) 4799f7d47b0SAlexander V. Chernikov { 4809f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 4819f7d47b0SAlexander V. Chernikov struct radix_node *rn; 4829f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 4839f7d47b0SAlexander V. Chernikov 4849f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 4859f7d47b0SAlexander V. Chernikov 486ac35ff17SAlexander V. Chernikov if (tei->subtype == AF_INET) 4879f7d47b0SAlexander V. Chernikov rnh = ti->state; 4889f7d47b0SAlexander V. Chernikov else 4899f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 4909f7d47b0SAlexander V. Chernikov 4919f7d47b0SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh); 4929f7d47b0SAlexander V. Chernikov 4939f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 4949f7d47b0SAlexander V. Chernikov 4959f7d47b0SAlexander V. Chernikov if (rn == NULL) 49681d3153dSAlexander V. Chernikov return (ENOENT); 4979f7d47b0SAlexander V. Chernikov 4989f7d47b0SAlexander V. Chernikov return (0); 4999f7d47b0SAlexander V. Chernikov } 5009f7d47b0SAlexander V. Chernikov 5019f7d47b0SAlexander V. Chernikov static void 502*68394ec8SAlexander V. Chernikov ta_flush_cidr_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 503*68394ec8SAlexander V. Chernikov void *ta_buf) 5049f7d47b0SAlexander V. Chernikov { 5059f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 5069f7d47b0SAlexander V. Chernikov 5079f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 5089f7d47b0SAlexander V. Chernikov 509ac35ff17SAlexander V. Chernikov if (tb->ent_ptr != NULL) 5109f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 5119f7d47b0SAlexander V. Chernikov } 5129f7d47b0SAlexander V. Chernikov 5139f7d47b0SAlexander V. Chernikov struct table_algo radix_cidr = { 514ac35ff17SAlexander V. Chernikov .name = "radix_cidr", 5159f7d47b0SAlexander V. Chernikov .lookup = ta_lookup_radix, 5169f7d47b0SAlexander V. Chernikov .init = ta_init_radix, 5179f7d47b0SAlexander V. Chernikov .destroy = ta_destroy_radix, 5189f7d47b0SAlexander V. Chernikov .prepare_add = ta_prepare_add_cidr, 5199f7d47b0SAlexander V. Chernikov .prepare_del = ta_prepare_del_cidr, 5209f7d47b0SAlexander V. Chernikov .add = ta_add_cidr, 5219f7d47b0SAlexander V. Chernikov .del = ta_del_cidr, 5229f7d47b0SAlexander V. Chernikov .flush_entry = ta_flush_cidr_entry, 5239f7d47b0SAlexander V. Chernikov .foreach = ta_foreach_radix, 52481d3153dSAlexander V. Chernikov .dump_tentry = ta_dump_radix_tentry, 52581d3153dSAlexander V. Chernikov .find_tentry = ta_find_radix_tentry, 5269f7d47b0SAlexander V. Chernikov }; 5279f7d47b0SAlexander V. Chernikov 5289f7d47b0SAlexander V. Chernikov 5299f7d47b0SAlexander V. Chernikov /* 530*68394ec8SAlexander V. Chernikov * Iface table cmds. 531*68394ec8SAlexander V. Chernikov * 532*68394ec8SAlexander V. Chernikov * Implementation: 533*68394ec8SAlexander V. Chernikov * 534*68394ec8SAlexander V. Chernikov * Runtime part: 535*68394ec8SAlexander V. Chernikov * - sorted array of "struct ifidx" pointed by ti->state. 536*68394ec8SAlexander V. Chernikov * Array is allocated with routing up to IFIDX_CHUNK. Only existing 537*68394ec8SAlexander V. Chernikov * interfaces are stored in array, however its allocated size is 538*68394ec8SAlexander V. Chernikov * sufficient to hold all table records if needed. 539*68394ec8SAlexander V. Chernikov * - current array size is stored in ti->data 540*68394ec8SAlexander V. Chernikov * 541*68394ec8SAlexander V. Chernikov * Table data: 542*68394ec8SAlexander V. Chernikov * - "struct iftable_cfg" is allocated to store table state (ta_state). 543*68394ec8SAlexander V. Chernikov * - All table records are stored inside namedobj instance. 5449f7d47b0SAlexander V. Chernikov * 5459f7d47b0SAlexander V. Chernikov */ 5469f7d47b0SAlexander V. Chernikov 547*68394ec8SAlexander V. Chernikov struct ifidx { 548*68394ec8SAlexander V. Chernikov uint16_t kidx; 549*68394ec8SAlexander V. Chernikov uint16_t spare; 550*68394ec8SAlexander V. Chernikov uint32_t value; 551*68394ec8SAlexander V. Chernikov }; 552*68394ec8SAlexander V. Chernikov 553*68394ec8SAlexander V. Chernikov struct iftable_cfg; 554*68394ec8SAlexander V. Chernikov 555*68394ec8SAlexander V. Chernikov struct ifentry { 556*68394ec8SAlexander V. Chernikov struct named_object no; 557*68394ec8SAlexander V. Chernikov struct ipfw_ifc ic; 558*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 559*68394ec8SAlexander V. Chernikov TAILQ_ENTRY(ifentry) next; 560*68394ec8SAlexander V. Chernikov uint32_t value; 561*68394ec8SAlexander V. Chernikov int linked; 562*68394ec8SAlexander V. Chernikov }; 563*68394ec8SAlexander V. Chernikov 564*68394ec8SAlexander V. Chernikov struct iftable_cfg { 565*68394ec8SAlexander V. Chernikov struct namedobj_instance *ii; 566*68394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 567*68394ec8SAlexander V. Chernikov struct table_info *ti; 568*68394ec8SAlexander V. Chernikov void *main_ptr; 569*68394ec8SAlexander V. Chernikov size_t size; /* Number of items allocated in array */ 570*68394ec8SAlexander V. Chernikov size_t count; /* Number of all items */ 571*68394ec8SAlexander V. Chernikov size_t used; /* Number of items _active_ now */ 572*68394ec8SAlexander V. Chernikov }; 573*68394ec8SAlexander V. Chernikov 574*68394ec8SAlexander V. Chernikov #define IFIDX_CHUNK 16 575*68394ec8SAlexander V. Chernikov 576*68394ec8SAlexander V. Chernikov int compare_ifidx(const void *k, const void *v); 577*68394ec8SAlexander V. Chernikov static void if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex); 578*68394ec8SAlexander V. Chernikov 579*68394ec8SAlexander V. Chernikov int 580*68394ec8SAlexander V. Chernikov compare_ifidx(const void *k, const void *v) 581*68394ec8SAlexander V. Chernikov { 582*68394ec8SAlexander V. Chernikov struct ifidx *ifidx; 583*68394ec8SAlexander V. Chernikov uint16_t key; 584*68394ec8SAlexander V. Chernikov 585*68394ec8SAlexander V. Chernikov key = *((uint16_t *)k); 586*68394ec8SAlexander V. Chernikov ifidx = (struct ifidx *)v; 587*68394ec8SAlexander V. Chernikov 588*68394ec8SAlexander V. Chernikov if (key < ifidx->kidx) 589*68394ec8SAlexander V. Chernikov return (-1); 590*68394ec8SAlexander V. Chernikov else if (key > ifidx->kidx) 591*68394ec8SAlexander V. Chernikov return (1); 592*68394ec8SAlexander V. Chernikov 593*68394ec8SAlexander V. Chernikov return (0); 594*68394ec8SAlexander V. Chernikov } 595*68394ec8SAlexander V. Chernikov 596*68394ec8SAlexander V. Chernikov /* 597*68394ec8SAlexander V. Chernikov * Adds item @item with key @key into ascending-sorted array @base. 598*68394ec8SAlexander V. Chernikov * Assumes @base has enough additional storage. 599*68394ec8SAlexander V. Chernikov * 600*68394ec8SAlexander V. Chernikov * Returns 1 on success, 0 on duplicate key. 601*68394ec8SAlexander V. Chernikov */ 6029f7d47b0SAlexander V. Chernikov static int 603*68394ec8SAlexander V. Chernikov badd(const void *key, void *item, void *base, size_t nmemb, 604*68394ec8SAlexander V. Chernikov size_t size, int (*compar) (const void *, const void *)) 605*68394ec8SAlexander V. Chernikov { 606*68394ec8SAlexander V. Chernikov int min, max, mid, shift, res; 607*68394ec8SAlexander V. Chernikov caddr_t paddr; 608*68394ec8SAlexander V. Chernikov 609*68394ec8SAlexander V. Chernikov if (nmemb == 0) { 610*68394ec8SAlexander V. Chernikov memcpy(base, item, size); 611*68394ec8SAlexander V. Chernikov return (1); 612*68394ec8SAlexander V. Chernikov } 613*68394ec8SAlexander V. Chernikov 614*68394ec8SAlexander V. Chernikov /* Binary search */ 615*68394ec8SAlexander V. Chernikov min = 0; 616*68394ec8SAlexander V. Chernikov max = nmemb - 1; 617*68394ec8SAlexander V. Chernikov mid = 0; 618*68394ec8SAlexander V. Chernikov while (min <= max) { 619*68394ec8SAlexander V. Chernikov mid = (min + max) / 2; 620*68394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 621*68394ec8SAlexander V. Chernikov if (res == 0) 622*68394ec8SAlexander V. Chernikov return (0); 623*68394ec8SAlexander V. Chernikov 624*68394ec8SAlexander V. Chernikov if (res > 0) 625*68394ec8SAlexander V. Chernikov min = mid + 1; 626*68394ec8SAlexander V. Chernikov else 627*68394ec8SAlexander V. Chernikov max = mid - 1; 628*68394ec8SAlexander V. Chernikov } 629*68394ec8SAlexander V. Chernikov 630*68394ec8SAlexander V. Chernikov /* Item not found. */ 631*68394ec8SAlexander V. Chernikov res = compar(key, (const void *)((caddr_t)base + mid * size)); 632*68394ec8SAlexander V. Chernikov if (res > 0) 633*68394ec8SAlexander V. Chernikov shift = mid + 1; 634*68394ec8SAlexander V. Chernikov else 635*68394ec8SAlexander V. Chernikov shift = mid; 636*68394ec8SAlexander V. Chernikov 637*68394ec8SAlexander V. Chernikov paddr = (caddr_t)base + shift * size; 638*68394ec8SAlexander V. Chernikov if (nmemb > shift) 639*68394ec8SAlexander V. Chernikov memmove(paddr + size, paddr, (nmemb - shift) * size); 640*68394ec8SAlexander V. Chernikov 641*68394ec8SAlexander V. Chernikov memcpy(paddr, item, size); 642*68394ec8SAlexander V. Chernikov 643*68394ec8SAlexander V. Chernikov return (1); 644*68394ec8SAlexander V. Chernikov } 645*68394ec8SAlexander V. Chernikov 646*68394ec8SAlexander V. Chernikov /* 647*68394ec8SAlexander V. Chernikov * Deletes item with key @key from ascending-sorted array @base. 648*68394ec8SAlexander V. Chernikov * 649*68394ec8SAlexander V. Chernikov * Returns 1 on success, 0 for non-existent key. 650*68394ec8SAlexander V. Chernikov */ 651*68394ec8SAlexander V. Chernikov static int 652*68394ec8SAlexander V. Chernikov bdel(const void *key, void *base, size_t nmemb, size_t size, 653*68394ec8SAlexander V. Chernikov int (*compar) (const void *, const void *)) 654*68394ec8SAlexander V. Chernikov { 655*68394ec8SAlexander V. Chernikov caddr_t item; 656*68394ec8SAlexander V. Chernikov size_t sz; 657*68394ec8SAlexander V. Chernikov 658*68394ec8SAlexander V. Chernikov item = (caddr_t)bsearch(key, base, nmemb, size, compar); 659*68394ec8SAlexander V. Chernikov 660*68394ec8SAlexander V. Chernikov if (item == NULL) 661*68394ec8SAlexander V. Chernikov return (0); 662*68394ec8SAlexander V. Chernikov 663*68394ec8SAlexander V. Chernikov sz = (caddr_t)base + nmemb * size - item; 664*68394ec8SAlexander V. Chernikov 665*68394ec8SAlexander V. Chernikov if (sz > 0) 666*68394ec8SAlexander V. Chernikov memmove(item, item + size, sz); 667*68394ec8SAlexander V. Chernikov 668*68394ec8SAlexander V. Chernikov return (1); 669*68394ec8SAlexander V. Chernikov } 670*68394ec8SAlexander V. Chernikov 671*68394ec8SAlexander V. Chernikov static struct ifidx * 672*68394ec8SAlexander V. Chernikov ifidx_find(struct table_info *ti, void *key) 673*68394ec8SAlexander V. Chernikov { 674*68394ec8SAlexander V. Chernikov struct ifidx *ifi; 675*68394ec8SAlexander V. Chernikov 676*68394ec8SAlexander V. Chernikov ifi = bsearch(key, ti->state, ti->data, sizeof(struct ifidx), 677*68394ec8SAlexander V. Chernikov compare_ifidx); 678*68394ec8SAlexander V. Chernikov 679*68394ec8SAlexander V. Chernikov return (ifi); 680*68394ec8SAlexander V. Chernikov } 681*68394ec8SAlexander V. Chernikov 682*68394ec8SAlexander V. Chernikov static int 683*68394ec8SAlexander V. Chernikov ta_lookup_ifidx(struct table_info *ti, void *key, uint32_t keylen, 6849f7d47b0SAlexander V. Chernikov uint32_t *val) 6859f7d47b0SAlexander V. Chernikov { 686*68394ec8SAlexander V. Chernikov struct ifidx *ifi; 6879f7d47b0SAlexander V. Chernikov 688*68394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, key); 6899f7d47b0SAlexander V. Chernikov 690*68394ec8SAlexander V. Chernikov if (ifi != NULL) { 691*68394ec8SAlexander V. Chernikov *val = ifi->value; 6929f7d47b0SAlexander V. Chernikov return (1); 6939f7d47b0SAlexander V. Chernikov } 6949f7d47b0SAlexander V. Chernikov 6959f7d47b0SAlexander V. Chernikov return (0); 6969f7d47b0SAlexander V. Chernikov } 6979f7d47b0SAlexander V. Chernikov 6989f7d47b0SAlexander V. Chernikov static int 699*68394ec8SAlexander V. Chernikov ta_init_ifidx(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, 700*68394ec8SAlexander V. Chernikov char *data) 7019f7d47b0SAlexander V. Chernikov { 702*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 7039f7d47b0SAlexander V. Chernikov 704*68394ec8SAlexander V. Chernikov icfg = malloc(sizeof(struct iftable_cfg), M_IPFW, M_WAITOK | M_ZERO); 7059f7d47b0SAlexander V. Chernikov 706*68394ec8SAlexander V. Chernikov icfg->ii = ipfw_objhash_create(16); 707*68394ec8SAlexander V. Chernikov icfg->main_ptr = malloc(sizeof(struct ifidx) * IFIDX_CHUNK, M_IPFW, 708*68394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 709*68394ec8SAlexander V. Chernikov icfg->size = IFIDX_CHUNK; 710*68394ec8SAlexander V. Chernikov icfg->ch = ch; 7119f7d47b0SAlexander V. Chernikov 712*68394ec8SAlexander V. Chernikov *ta_state = icfg; 713*68394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 714*68394ec8SAlexander V. Chernikov ti->lookup = ta_lookup_ifidx; 7159f7d47b0SAlexander V. Chernikov 7169f7d47b0SAlexander V. Chernikov return (0); 7179f7d47b0SAlexander V. Chernikov } 7189f7d47b0SAlexander V. Chernikov 719*68394ec8SAlexander V. Chernikov /* 720*68394ec8SAlexander V. Chernikov * Handle tableinfo @ti pointer change (on table array resize). 721*68394ec8SAlexander V. Chernikov */ 722*68394ec8SAlexander V. Chernikov static void 723*68394ec8SAlexander V. Chernikov ta_change_ti_ifidx(void *ta_state, struct table_info *ti) 724*68394ec8SAlexander V. Chernikov { 725*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 726*68394ec8SAlexander V. Chernikov 727*68394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 728*68394ec8SAlexander V. Chernikov icfg->ti = ti; 729*68394ec8SAlexander V. Chernikov } 7309f7d47b0SAlexander V. Chernikov 7319f7d47b0SAlexander V. Chernikov static void 732*68394ec8SAlexander V. Chernikov destroy_ifidx_locked(struct namedobj_instance *ii, struct named_object *no, 733*68394ec8SAlexander V. Chernikov void *arg) 7349f7d47b0SAlexander V. Chernikov { 735*68394ec8SAlexander V. Chernikov struct ifentry *ife; 736*68394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 7379f7d47b0SAlexander V. Chernikov 738*68394ec8SAlexander V. Chernikov ch = (struct ip_fw_chain *)arg; 739*68394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 740*68394ec8SAlexander V. Chernikov 741*68394ec8SAlexander V. Chernikov ipfw_iface_del_notify(ch, &ife->ic); 742*68394ec8SAlexander V. Chernikov free(ife, M_IPFW_TBL); 7439f7d47b0SAlexander V. Chernikov } 7449f7d47b0SAlexander V. Chernikov 745*68394ec8SAlexander V. Chernikov 746*68394ec8SAlexander V. Chernikov /* 747*68394ec8SAlexander V. Chernikov * Destroys table @ti 748*68394ec8SAlexander V. Chernikov */ 749*68394ec8SAlexander V. Chernikov static void 750*68394ec8SAlexander V. Chernikov ta_destroy_ifidx(void *ta_state, struct table_info *ti) 7519f7d47b0SAlexander V. Chernikov { 752*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 753*68394ec8SAlexander V. Chernikov struct ip_fw_chain *ch; 754*68394ec8SAlexander V. Chernikov 755*68394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 756*68394ec8SAlexander V. Chernikov ch = icfg->ch; 757*68394ec8SAlexander V. Chernikov 758*68394ec8SAlexander V. Chernikov if (icfg->main_ptr != NULL) 759*68394ec8SAlexander V. Chernikov free(icfg->main_ptr, M_IPFW); 760*68394ec8SAlexander V. Chernikov 761*68394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, destroy_ifidx_locked, ch); 762*68394ec8SAlexander V. Chernikov 763*68394ec8SAlexander V. Chernikov ipfw_objhash_destroy(icfg->ii); 764*68394ec8SAlexander V. Chernikov 765*68394ec8SAlexander V. Chernikov free(icfg, M_IPFW); 766*68394ec8SAlexander V. Chernikov } 767*68394ec8SAlexander V. Chernikov 768*68394ec8SAlexander V. Chernikov struct ta_buf_ifidx 769*68394ec8SAlexander V. Chernikov { 770*68394ec8SAlexander V. Chernikov struct ifentry *ife; 771*68394ec8SAlexander V. Chernikov uint32_t value; 7729f7d47b0SAlexander V. Chernikov }; 7739f7d47b0SAlexander V. Chernikov 774*68394ec8SAlexander V. Chernikov /* 775*68394ec8SAlexander V. Chernikov * Prepare state to add to the table: 776*68394ec8SAlexander V. Chernikov * allocate ifentry and reference needed interface. 777*68394ec8SAlexander V. Chernikov */ 7789f7d47b0SAlexander V. Chernikov static int 779*68394ec8SAlexander V. Chernikov ta_prepare_add_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 780*68394ec8SAlexander V. Chernikov void *ta_buf) 781*68394ec8SAlexander V. Chernikov { 782*68394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 783*68394ec8SAlexander V. Chernikov char *ifname; 784*68394ec8SAlexander V. Chernikov struct ifentry *ife; 785*68394ec8SAlexander V. Chernikov 786*68394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 787*68394ec8SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 788*68394ec8SAlexander V. Chernikov 789*68394ec8SAlexander V. Chernikov /* Check if string is terminated */ 790*68394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 791*68394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 792*68394ec8SAlexander V. Chernikov return (EINVAL); 793*68394ec8SAlexander V. Chernikov 794*68394ec8SAlexander V. Chernikov ife = malloc(sizeof(struct ifentry), M_IPFW_TBL, M_WAITOK | M_ZERO); 795*68394ec8SAlexander V. Chernikov ife->value = tei->value; 796*68394ec8SAlexander V. Chernikov ife->ic.cb = if_notifier; 797*68394ec8SAlexander V. Chernikov ife->ic.cbdata = ife; 798*68394ec8SAlexander V. Chernikov 799*68394ec8SAlexander V. Chernikov if (ipfw_iface_ref(ch, ifname, &ife->ic) != 0) 800*68394ec8SAlexander V. Chernikov return (EINVAL); 801*68394ec8SAlexander V. Chernikov 802*68394ec8SAlexander V. Chernikov /* Use ipfw_iface 'ifname' field as stable storage */ 803*68394ec8SAlexander V. Chernikov ife->no.name = ife->ic.iface->ifname; 804*68394ec8SAlexander V. Chernikov 805*68394ec8SAlexander V. Chernikov tb->ife = ife; 806*68394ec8SAlexander V. Chernikov 807*68394ec8SAlexander V. Chernikov return (0); 808*68394ec8SAlexander V. Chernikov } 809*68394ec8SAlexander V. Chernikov 810*68394ec8SAlexander V. Chernikov static int 811*68394ec8SAlexander V. Chernikov ta_add_ifidx(void *ta_state, struct table_info *ti, 812*68394ec8SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint64_t *pflags) 813*68394ec8SAlexander V. Chernikov { 814*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 815*68394ec8SAlexander V. Chernikov struct ifentry *ife, *tmp; 816*68394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 817*68394ec8SAlexander V. Chernikov struct ipfw_iface *iif; 818*68394ec8SAlexander V. Chernikov struct ifidx *ifi; 819*68394ec8SAlexander V. Chernikov char *ifname; 820*68394ec8SAlexander V. Chernikov 821*68394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 822*68394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 823*68394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 824*68394ec8SAlexander V. Chernikov ife = tb->ife; 825*68394ec8SAlexander V. Chernikov 826*68394ec8SAlexander V. Chernikov ife->icfg = icfg; 827*68394ec8SAlexander V. Chernikov 828*68394ec8SAlexander V. Chernikov tmp = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 829*68394ec8SAlexander V. Chernikov 830*68394ec8SAlexander V. Chernikov if (tmp != NULL) { 831*68394ec8SAlexander V. Chernikov if ((tei->flags & TEI_FLAGS_UPDATE) == 0) 832*68394ec8SAlexander V. Chernikov return (EEXIST); 833*68394ec8SAlexander V. Chernikov 834*68394ec8SAlexander V. Chernikov /* We need to update value */ 835*68394ec8SAlexander V. Chernikov iif = tmp->ic.iface; 836*68394ec8SAlexander V. Chernikov tmp->value = ife->value; 837*68394ec8SAlexander V. Chernikov 838*68394ec8SAlexander V. Chernikov if (iif->resolved != 0) { 839*68394ec8SAlexander V. Chernikov /* We need to update runtime value, too */ 840*68394ec8SAlexander V. Chernikov ifi = ifidx_find(ti, &iif->ifindex); 841*68394ec8SAlexander V. Chernikov ifi->value = ife->value; 842*68394ec8SAlexander V. Chernikov } 843*68394ec8SAlexander V. Chernikov 844*68394ec8SAlexander V. Chernikov /* Indicate that update has happened instead of addition */ 845*68394ec8SAlexander V. Chernikov tei->flags |= TEI_FLAGS_UPDATED; 846*68394ec8SAlexander V. Chernikov return (0); 847*68394ec8SAlexander V. Chernikov } 848*68394ec8SAlexander V. Chernikov 849*68394ec8SAlexander V. Chernikov /* Link to internal list */ 850*68394ec8SAlexander V. Chernikov ipfw_objhash_add(icfg->ii, &ife->no); 851*68394ec8SAlexander V. Chernikov 852*68394ec8SAlexander V. Chernikov /* Link notifier (possible running its callback) */ 853*68394ec8SAlexander V. Chernikov ipfw_iface_add_notify(icfg->ch, &ife->ic); 854*68394ec8SAlexander V. Chernikov icfg->count++; 855*68394ec8SAlexander V. Chernikov 856*68394ec8SAlexander V. Chernikov if (icfg->count + 1 == icfg->size) { 857*68394ec8SAlexander V. Chernikov /* Notify core we need to grow */ 858*68394ec8SAlexander V. Chernikov *pflags = icfg->size + IFIDX_CHUNK; 859*68394ec8SAlexander V. Chernikov } 860*68394ec8SAlexander V. Chernikov 861*68394ec8SAlexander V. Chernikov tb->ife = NULL; 862*68394ec8SAlexander V. Chernikov 863*68394ec8SAlexander V. Chernikov return (0); 864*68394ec8SAlexander V. Chernikov } 865*68394ec8SAlexander V. Chernikov 866*68394ec8SAlexander V. Chernikov /* 867*68394ec8SAlexander V. Chernikov * Prepare to delete key from table. 868*68394ec8SAlexander V. Chernikov * Do basic interface name checks. 869*68394ec8SAlexander V. Chernikov */ 870*68394ec8SAlexander V. Chernikov static int 871*68394ec8SAlexander V. Chernikov ta_prepare_del_ifidx(struct ip_fw_chain *ch, struct tentry_info *tei, 872*68394ec8SAlexander V. Chernikov void *ta_buf) 8739f7d47b0SAlexander V. Chernikov { 8749f7d47b0SAlexander V. Chernikov struct ta_buf_iface *tb; 875e0a8b9eeSAlexander V. Chernikov char *ifname; 8769f7d47b0SAlexander V. Chernikov 8779f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_iface *)ta_buf; 8789f7d47b0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 8799f7d47b0SAlexander V. Chernikov 8809f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 881e0a8b9eeSAlexander V. Chernikov ifname = (char *)tei->paddr; 882e0a8b9eeSAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 8839f7d47b0SAlexander V. Chernikov return (EINVAL); 8849f7d47b0SAlexander V. Chernikov 8859f7d47b0SAlexander V. Chernikov return (0); 8869f7d47b0SAlexander V. Chernikov } 8879f7d47b0SAlexander V. Chernikov 888*68394ec8SAlexander V. Chernikov /* 889*68394ec8SAlexander V. Chernikov * Remove key from both configuration list and 890*68394ec8SAlexander V. Chernikov * runtime array. Removed interface notification. 891*68394ec8SAlexander V. Chernikov */ 8929f7d47b0SAlexander V. Chernikov static int 893*68394ec8SAlexander V. Chernikov ta_del_ifidx(void *ta_state, struct table_info *ti, 894db785d31SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf, uint64_t *pflags) 8959f7d47b0SAlexander V. Chernikov { 896*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 897*68394ec8SAlexander V. Chernikov struct ifentry *ife; 898*68394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 899*68394ec8SAlexander V. Chernikov char *ifname; 900*68394ec8SAlexander V. Chernikov uint16_t ifindex; 901*68394ec8SAlexander V. Chernikov int res; 9029f7d47b0SAlexander V. Chernikov 903*68394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 904*68394ec8SAlexander V. Chernikov ifname = (char *)tei->paddr; 905*68394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 906*68394ec8SAlexander V. Chernikov ife = tb->ife; 9079f7d47b0SAlexander V. Chernikov 908*68394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 9099f7d47b0SAlexander V. Chernikov 910*68394ec8SAlexander V. Chernikov if (ife == NULL) 91181d3153dSAlexander V. Chernikov return (ENOENT); 9129f7d47b0SAlexander V. Chernikov 913*68394ec8SAlexander V. Chernikov if (ife->linked != 0) { 914*68394ec8SAlexander V. Chernikov /* We have to remove item from runtime */ 915*68394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 916*68394ec8SAlexander V. Chernikov 917*68394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 918*68394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 919*68394ec8SAlexander V. Chernikov 920*68394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 921*68394ec8SAlexander V. Chernikov icfg->used--; 922*68394ec8SAlexander V. Chernikov ti->data = icfg->used; 923*68394ec8SAlexander V. Chernikov ife->linked = 0; 924*68394ec8SAlexander V. Chernikov } 925*68394ec8SAlexander V. Chernikov 926*68394ec8SAlexander V. Chernikov /* Unlink from local list */ 927*68394ec8SAlexander V. Chernikov ipfw_objhash_del(icfg->ii, &ife->no); 928*68394ec8SAlexander V. Chernikov /* Unlink notifier */ 929*68394ec8SAlexander V. Chernikov ipfw_iface_del_notify(icfg->ch, &ife->ic); 930*68394ec8SAlexander V. Chernikov 931*68394ec8SAlexander V. Chernikov icfg->count--; 932*68394ec8SAlexander V. Chernikov 933*68394ec8SAlexander V. Chernikov tb->ife = ife; 934*68394ec8SAlexander V. Chernikov 9359f7d47b0SAlexander V. Chernikov return (0); 9369f7d47b0SAlexander V. Chernikov } 9379f7d47b0SAlexander V. Chernikov 938*68394ec8SAlexander V. Chernikov /* 939*68394ec8SAlexander V. Chernikov * Flush deleted entry. 940*68394ec8SAlexander V. Chernikov * Drops interface reference and frees entry. 941*68394ec8SAlexander V. Chernikov */ 9429f7d47b0SAlexander V. Chernikov static void 943*68394ec8SAlexander V. Chernikov ta_flush_ifidx_entry(struct ip_fw_chain *ch, struct tentry_info *tei, 944*68394ec8SAlexander V. Chernikov void *ta_buf) 9459f7d47b0SAlexander V. Chernikov { 946*68394ec8SAlexander V. Chernikov struct ta_buf_ifidx *tb; 9479f7d47b0SAlexander V. Chernikov 948*68394ec8SAlexander V. Chernikov tb = (struct ta_buf_ifidx *)ta_buf; 9499f7d47b0SAlexander V. Chernikov 950*68394ec8SAlexander V. Chernikov if (tb->ife != NULL) { 951*68394ec8SAlexander V. Chernikov /* Unlink first */ 952*68394ec8SAlexander V. Chernikov ipfw_iface_unref(ch, &tb->ife->ic); 953*68394ec8SAlexander V. Chernikov free(tb->ife, M_IPFW_TBL); 954*68394ec8SAlexander V. Chernikov } 955*68394ec8SAlexander V. Chernikov } 956*68394ec8SAlexander V. Chernikov 957*68394ec8SAlexander V. Chernikov 958*68394ec8SAlexander V. Chernikov /* 959*68394ec8SAlexander V. Chernikov * Handle interface announce/withdrawal for particular table. 960*68394ec8SAlexander V. Chernikov * Every real runtime array modification happens here. 961*68394ec8SAlexander V. Chernikov */ 962*68394ec8SAlexander V. Chernikov static void 963*68394ec8SAlexander V. Chernikov if_notifier(struct ip_fw_chain *ch, void *cbdata, uint16_t ifindex) 964*68394ec8SAlexander V. Chernikov { 965*68394ec8SAlexander V. Chernikov struct ifentry *ife; 966*68394ec8SAlexander V. Chernikov struct ifidx ifi; 967*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 968*68394ec8SAlexander V. Chernikov struct table_info *ti; 969*68394ec8SAlexander V. Chernikov int res; 970*68394ec8SAlexander V. Chernikov 971*68394ec8SAlexander V. Chernikov ife = (struct ifentry *)cbdata; 972*68394ec8SAlexander V. Chernikov icfg = ife->icfg; 973*68394ec8SAlexander V. Chernikov ti = icfg->ti; 974*68394ec8SAlexander V. Chernikov 975*68394ec8SAlexander V. Chernikov KASSERT(ti != NULL, ("ti=NULL, check change_ti handler")); 976*68394ec8SAlexander V. Chernikov 977*68394ec8SAlexander V. Chernikov if (ife->linked == 0 && ifindex != 0) { 978*68394ec8SAlexander V. Chernikov /* Interface announce */ 979*68394ec8SAlexander V. Chernikov ifi.kidx = ifindex; 980*68394ec8SAlexander V. Chernikov ifi.spare = 0; 981*68394ec8SAlexander V. Chernikov ifi.value = ife->value; 982*68394ec8SAlexander V. Chernikov res = badd(&ifindex, &ifi, icfg->main_ptr, icfg->used, 983*68394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 984*68394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d already exists", ifindex)); 985*68394ec8SAlexander V. Chernikov icfg->used++; 986*68394ec8SAlexander V. Chernikov ti->data = icfg->used; 987*68394ec8SAlexander V. Chernikov ife->linked = 1; 988*68394ec8SAlexander V. Chernikov } else if (ife->linked != 0 && ifindex == 0) { 989*68394ec8SAlexander V. Chernikov /* Interface withdrawal */ 990*68394ec8SAlexander V. Chernikov ifindex = ife->ic.iface->ifindex; 991*68394ec8SAlexander V. Chernikov 992*68394ec8SAlexander V. Chernikov res = bdel(&ifindex, icfg->main_ptr, icfg->used, 993*68394ec8SAlexander V. Chernikov sizeof(struct ifidx), compare_ifidx); 994*68394ec8SAlexander V. Chernikov 995*68394ec8SAlexander V. Chernikov KASSERT(res == 1, ("index %d does not exist", ifindex)); 996*68394ec8SAlexander V. Chernikov icfg->used--; 997*68394ec8SAlexander V. Chernikov ti->data = icfg->used; 998*68394ec8SAlexander V. Chernikov ife->linked = 0; 999*68394ec8SAlexander V. Chernikov } 1000*68394ec8SAlexander V. Chernikov } 1001*68394ec8SAlexander V. Chernikov 1002*68394ec8SAlexander V. Chernikov 1003*68394ec8SAlexander V. Chernikov /* 1004*68394ec8SAlexander V. Chernikov * Table growing callbacks. 1005*68394ec8SAlexander V. Chernikov */ 1006*68394ec8SAlexander V. Chernikov 1007*68394ec8SAlexander V. Chernikov struct mod_ifidx { 1008*68394ec8SAlexander V. Chernikov void *main_ptr; 1009*68394ec8SAlexander V. Chernikov size_t size; 1010*68394ec8SAlexander V. Chernikov }; 1011*68394ec8SAlexander V. Chernikov 1012*68394ec8SAlexander V. Chernikov /* 1013*68394ec8SAlexander V. Chernikov * Allocate ned, larger runtime ifidx array. 1014*68394ec8SAlexander V. Chernikov */ 1015*68394ec8SAlexander V. Chernikov static int 1016*68394ec8SAlexander V. Chernikov ta_prepare_mod_ifidx(void *ta_buf, uint64_t *pflags) 1017*68394ec8SAlexander V. Chernikov { 1018*68394ec8SAlexander V. Chernikov struct mod_ifidx *mi; 1019*68394ec8SAlexander V. Chernikov 1020*68394ec8SAlexander V. Chernikov mi = (struct mod_ifidx *)ta_buf; 1021*68394ec8SAlexander V. Chernikov 1022*68394ec8SAlexander V. Chernikov memset(mi, 0, sizeof(struct mod_ifidx)); 1023*68394ec8SAlexander V. Chernikov mi->size = *pflags; 1024*68394ec8SAlexander V. Chernikov mi->main_ptr = malloc(sizeof(struct ifidx) * mi->size, M_IPFW, 1025*68394ec8SAlexander V. Chernikov M_WAITOK | M_ZERO); 1026*68394ec8SAlexander V. Chernikov 1027*68394ec8SAlexander V. Chernikov return (0); 1028*68394ec8SAlexander V. Chernikov } 1029*68394ec8SAlexander V. Chernikov 1030*68394ec8SAlexander V. Chernikov /* 1031*68394ec8SAlexander V. Chernikov * Copy data from old runtime array to new one. 1032*68394ec8SAlexander V. Chernikov */ 1033*68394ec8SAlexander V. Chernikov static int 1034*68394ec8SAlexander V. Chernikov ta_fill_mod_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 1035*68394ec8SAlexander V. Chernikov uint64_t *pflags) 1036*68394ec8SAlexander V. Chernikov { 1037*68394ec8SAlexander V. Chernikov struct mod_ifidx *mi; 1038*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 1039*68394ec8SAlexander V. Chernikov 1040*68394ec8SAlexander V. Chernikov mi = (struct mod_ifidx *)ta_buf; 1041*68394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 1042*68394ec8SAlexander V. Chernikov 1043*68394ec8SAlexander V. Chernikov /* Check if we still need to grow array */ 1044*68394ec8SAlexander V. Chernikov if (icfg->size >= mi->size) { 1045*68394ec8SAlexander V. Chernikov *pflags = 0; 1046*68394ec8SAlexander V. Chernikov return (0); 1047*68394ec8SAlexander V. Chernikov } 1048*68394ec8SAlexander V. Chernikov 1049*68394ec8SAlexander V. Chernikov memcpy(mi->main_ptr, icfg->main_ptr, icfg->used * sizeof(struct ifidx)); 1050*68394ec8SAlexander V. Chernikov 1051*68394ec8SAlexander V. Chernikov return (0); 1052*68394ec8SAlexander V. Chernikov } 1053*68394ec8SAlexander V. Chernikov 1054*68394ec8SAlexander V. Chernikov /* 1055*68394ec8SAlexander V. Chernikov * Switch old & new arrays. 1056*68394ec8SAlexander V. Chernikov */ 1057*68394ec8SAlexander V. Chernikov static int 1058*68394ec8SAlexander V. Chernikov ta_modify_ifidx(void *ta_state, struct table_info *ti, void *ta_buf, 1059*68394ec8SAlexander V. Chernikov uint64_t pflags) 1060*68394ec8SAlexander V. Chernikov { 1061*68394ec8SAlexander V. Chernikov struct mod_ifidx *mi; 1062*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 1063*68394ec8SAlexander V. Chernikov void *old_ptr; 1064*68394ec8SAlexander V. Chernikov 1065*68394ec8SAlexander V. Chernikov mi = (struct mod_ifidx *)ta_buf; 1066*68394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 1067*68394ec8SAlexander V. Chernikov 1068*68394ec8SAlexander V. Chernikov old_ptr = icfg->main_ptr; 1069*68394ec8SAlexander V. Chernikov icfg->main_ptr = mi->main_ptr; 1070*68394ec8SAlexander V. Chernikov icfg->size = mi->size; 1071*68394ec8SAlexander V. Chernikov ti->state = icfg->main_ptr; 1072*68394ec8SAlexander V. Chernikov 1073*68394ec8SAlexander V. Chernikov mi->main_ptr = old_ptr; 1074*68394ec8SAlexander V. Chernikov 1075*68394ec8SAlexander V. Chernikov return (0); 1076*68394ec8SAlexander V. Chernikov } 1077*68394ec8SAlexander V. Chernikov 1078*68394ec8SAlexander V. Chernikov /* 1079*68394ec8SAlexander V. Chernikov * Free unneded array. 1080*68394ec8SAlexander V. Chernikov */ 1081*68394ec8SAlexander V. Chernikov static void 1082*68394ec8SAlexander V. Chernikov ta_flush_mod_ifidx(void *ta_buf) 1083*68394ec8SAlexander V. Chernikov { 1084*68394ec8SAlexander V. Chernikov struct mod_ifidx *mi; 1085*68394ec8SAlexander V. Chernikov 1086*68394ec8SAlexander V. Chernikov mi = (struct mod_ifidx *)ta_buf; 1087*68394ec8SAlexander V. Chernikov if (mi->main_ptr != NULL) 1088*68394ec8SAlexander V. Chernikov free(mi->main_ptr, M_IPFW); 10899f7d47b0SAlexander V. Chernikov } 10909f7d47b0SAlexander V. Chernikov 10919f7d47b0SAlexander V. Chernikov static int 1092*68394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(void *ta_state, struct table_info *ti, void *e, 109381d3153dSAlexander V. Chernikov ipfw_obj_tentry *tent) 10949f7d47b0SAlexander V. Chernikov { 1095*68394ec8SAlexander V. Chernikov struct ifentry *ife; 10969f7d47b0SAlexander V. Chernikov 1097*68394ec8SAlexander V. Chernikov ife = (struct ifentry *)e; 1098*68394ec8SAlexander V. Chernikov 109981d3153dSAlexander V. Chernikov tent->masklen = 8 * IF_NAMESIZE; 1100*68394ec8SAlexander V. Chernikov memcpy(&tent->k, ife->no.name, IF_NAMESIZE); 1101*68394ec8SAlexander V. Chernikov tent->value = ife->value; 11029f7d47b0SAlexander V. Chernikov 11039f7d47b0SAlexander V. Chernikov return (0); 11049f7d47b0SAlexander V. Chernikov } 11059f7d47b0SAlexander V. Chernikov 110681d3153dSAlexander V. Chernikov static int 1107*68394ec8SAlexander V. Chernikov ta_find_ifidx_tentry(void *ta_state, struct table_info *ti, void *key, 110881d3153dSAlexander V. Chernikov uint32_t keylen, ipfw_obj_tentry *tent) 110981d3153dSAlexander V. Chernikov { 1110*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 1111*68394ec8SAlexander V. Chernikov struct ifentry *ife; 1112*68394ec8SAlexander V. Chernikov char *ifname; 111381d3153dSAlexander V. Chernikov 1114*68394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 1115*68394ec8SAlexander V. Chernikov ifname = (char *)key; 111681d3153dSAlexander V. Chernikov 1117*68394ec8SAlexander V. Chernikov if (strnlen(ifname, IF_NAMESIZE) == IF_NAMESIZE) 1118*68394ec8SAlexander V. Chernikov return (EINVAL); 111981d3153dSAlexander V. Chernikov 1120*68394ec8SAlexander V. Chernikov ife = (struct ifentry *)ipfw_objhash_lookup_name(icfg->ii, 0, ifname); 1121*68394ec8SAlexander V. Chernikov 1122*68394ec8SAlexander V. Chernikov if (ife != NULL) { 1123*68394ec8SAlexander V. Chernikov ta_dump_ifidx_tentry(ta_state, ti, ife, tent); 112481d3153dSAlexander V. Chernikov return (0); 112581d3153dSAlexander V. Chernikov } 112681d3153dSAlexander V. Chernikov 112781d3153dSAlexander V. Chernikov return (ENOENT); 112881d3153dSAlexander V. Chernikov } 112981d3153dSAlexander V. Chernikov 1130*68394ec8SAlexander V. Chernikov struct wa_ifidx { 1131*68394ec8SAlexander V. Chernikov ta_foreach_f *f; 1132*68394ec8SAlexander V. Chernikov void *arg; 1133*68394ec8SAlexander V. Chernikov }; 1134*68394ec8SAlexander V. Chernikov 11359f7d47b0SAlexander V. Chernikov static void 1136*68394ec8SAlexander V. Chernikov foreach_ifidx(struct namedobj_instance *ii, struct named_object *no, 11379f7d47b0SAlexander V. Chernikov void *arg) 11389f7d47b0SAlexander V. Chernikov { 1139*68394ec8SAlexander V. Chernikov struct ifentry *ife; 1140*68394ec8SAlexander V. Chernikov struct wa_ifidx *wa; 11419f7d47b0SAlexander V. Chernikov 1142*68394ec8SAlexander V. Chernikov ife = (struct ifentry *)no; 1143*68394ec8SAlexander V. Chernikov wa = (struct wa_ifidx *)arg; 1144*68394ec8SAlexander V. Chernikov 1145*68394ec8SAlexander V. Chernikov wa->f(ife, wa->arg); 11469f7d47b0SAlexander V. Chernikov } 11479f7d47b0SAlexander V. Chernikov 1148*68394ec8SAlexander V. Chernikov static void 1149*68394ec8SAlexander V. Chernikov ta_foreach_ifidx(void *ta_state, struct table_info *ti, ta_foreach_f *f, 1150*68394ec8SAlexander V. Chernikov void *arg) 1151*68394ec8SAlexander V. Chernikov { 1152*68394ec8SAlexander V. Chernikov struct iftable_cfg *icfg; 1153*68394ec8SAlexander V. Chernikov struct wa_ifidx wa; 1154*68394ec8SAlexander V. Chernikov 1155*68394ec8SAlexander V. Chernikov icfg = (struct iftable_cfg *)ta_state; 1156*68394ec8SAlexander V. Chernikov 1157*68394ec8SAlexander V. Chernikov wa.f = f; 1158*68394ec8SAlexander V. Chernikov wa.arg = arg; 1159*68394ec8SAlexander V. Chernikov 1160*68394ec8SAlexander V. Chernikov ipfw_objhash_foreach(icfg->ii, foreach_ifidx, &wa); 1161*68394ec8SAlexander V. Chernikov } 1162*68394ec8SAlexander V. Chernikov 1163*68394ec8SAlexander V. Chernikov struct table_algo idx_iface = { 1164*68394ec8SAlexander V. Chernikov .name = "idx_iface", 1165*68394ec8SAlexander V. Chernikov .lookup = ta_lookup_ifidx, 1166*68394ec8SAlexander V. Chernikov .init = ta_init_ifidx, 1167*68394ec8SAlexander V. Chernikov .destroy = ta_destroy_ifidx, 1168*68394ec8SAlexander V. Chernikov .prepare_add = ta_prepare_add_ifidx, 1169*68394ec8SAlexander V. Chernikov .prepare_del = ta_prepare_del_ifidx, 1170*68394ec8SAlexander V. Chernikov .add = ta_add_ifidx, 1171*68394ec8SAlexander V. Chernikov .del = ta_del_ifidx, 1172*68394ec8SAlexander V. Chernikov .flush_entry = ta_flush_ifidx_entry, 1173*68394ec8SAlexander V. Chernikov .foreach = ta_foreach_ifidx, 1174*68394ec8SAlexander V. Chernikov .dump_tentry = ta_dump_ifidx_tentry, 1175*68394ec8SAlexander V. Chernikov .find_tentry = ta_find_ifidx_tentry, 1176*68394ec8SAlexander V. Chernikov .prepare_mod = ta_prepare_mod_ifidx, 1177*68394ec8SAlexander V. Chernikov .fill_mod = ta_fill_mod_ifidx, 1178*68394ec8SAlexander V. Chernikov .modify = ta_modify_ifidx, 1179*68394ec8SAlexander V. Chernikov .flush_mod = ta_flush_mod_ifidx, 1180*68394ec8SAlexander V. Chernikov .change_ti = ta_change_ti_ifidx, 11819f7d47b0SAlexander V. Chernikov }; 11829f7d47b0SAlexander V. Chernikov 11839f7d47b0SAlexander V. Chernikov void 11849f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *chain) 11859f7d47b0SAlexander V. Chernikov { 11869f7d47b0SAlexander V. Chernikov /* 11879f7d47b0SAlexander V. Chernikov * Register all algorithms presented here. 11889f7d47b0SAlexander V. Chernikov */ 11899f7d47b0SAlexander V. Chernikov ipfw_add_table_algo(chain, &radix_cidr); 1190*68394ec8SAlexander V. Chernikov ipfw_add_table_algo(chain, &idx_iface); 11919f7d47b0SAlexander V. Chernikov } 11929f7d47b0SAlexander V. Chernikov 11939f7d47b0SAlexander V. Chernikov void 11949f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *chain) 11959f7d47b0SAlexander V. Chernikov { 11969f7d47b0SAlexander V. Chernikov /* Do nothing */ 11979f7d47b0SAlexander V. Chernikov } 11989f7d47b0SAlexander V. Chernikov 11999f7d47b0SAlexander V. Chernikov 1200