1*9f7d47b0SAlexander V. Chernikov /*- 2*9f7d47b0SAlexander V. Chernikov * Copyright (c) 2004 Ruslan Ermilov and Vsevolod Lobko. 3*9f7d47b0SAlexander V. Chernikov * 4*9f7d47b0SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 5*9f7d47b0SAlexander V. Chernikov * modification, are permitted provided that the following conditions 6*9f7d47b0SAlexander V. Chernikov * are met: 7*9f7d47b0SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 8*9f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 9*9f7d47b0SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 10*9f7d47b0SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 11*9f7d47b0SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 12*9f7d47b0SAlexander V. Chernikov * 13*9f7d47b0SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*9f7d47b0SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*9f7d47b0SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*9f7d47b0SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17*9f7d47b0SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*9f7d47b0SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*9f7d47b0SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*9f7d47b0SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*9f7d47b0SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*9f7d47b0SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*9f7d47b0SAlexander V. Chernikov * SUCH DAMAGE. 24*9f7d47b0SAlexander V. Chernikov */ 25*9f7d47b0SAlexander V. Chernikov 26*9f7d47b0SAlexander V. Chernikov #include <sys/cdefs.h> 27*9f7d47b0SAlexander V. Chernikov __FBSDID("$FreeBSD: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c 267384 2014-06-12 09:59:11Z melifaro $"); 28*9f7d47b0SAlexander V. Chernikov 29*9f7d47b0SAlexander V. Chernikov /* 30*9f7d47b0SAlexander V. Chernikov * Lookup table algorithms. 31*9f7d47b0SAlexander V. Chernikov * 32*9f7d47b0SAlexander V. Chernikov * Lookup tables are implemented (at the moment) using the radix 33*9f7d47b0SAlexander V. Chernikov * tree used for routing tables. Tables store key-value entries, where 34*9f7d47b0SAlexander V. Chernikov * keys are network prefixes (addr/masklen), and values are integers. 35*9f7d47b0SAlexander V. Chernikov * As a degenerate case we can interpret keys as 32-bit integers 36*9f7d47b0SAlexander V. Chernikov * (with a /32 mask). 37*9f7d47b0SAlexander V. Chernikov * 38*9f7d47b0SAlexander V. Chernikov * The table is protected by the IPFW lock even for manipulation coming 39*9f7d47b0SAlexander V. Chernikov * from userland, because operations are typically fast. 40*9f7d47b0SAlexander V. Chernikov */ 41*9f7d47b0SAlexander V. Chernikov 42*9f7d47b0SAlexander V. Chernikov #include "opt_ipfw.h" 43*9f7d47b0SAlexander V. Chernikov #include "opt_inet.h" 44*9f7d47b0SAlexander V. Chernikov #ifndef INET 45*9f7d47b0SAlexander V. Chernikov #error IPFIREWALL requires INET. 46*9f7d47b0SAlexander V. Chernikov #endif /* INET */ 47*9f7d47b0SAlexander V. Chernikov #include "opt_inet6.h" 48*9f7d47b0SAlexander V. Chernikov 49*9f7d47b0SAlexander V. Chernikov #include <sys/param.h> 50*9f7d47b0SAlexander V. Chernikov #include <sys/systm.h> 51*9f7d47b0SAlexander V. Chernikov #include <sys/malloc.h> 52*9f7d47b0SAlexander V. Chernikov #include <sys/kernel.h> 53*9f7d47b0SAlexander V. Chernikov #include <sys/lock.h> 54*9f7d47b0SAlexander V. Chernikov #include <sys/rwlock.h> 55*9f7d47b0SAlexander V. Chernikov #include <sys/socket.h> 56*9f7d47b0SAlexander V. Chernikov #include <sys/queue.h> 57*9f7d47b0SAlexander V. Chernikov #include <net/if.h> /* ip_fw.h requires IFNAMSIZ */ 58*9f7d47b0SAlexander V. Chernikov #include <net/radix.h> 59*9f7d47b0SAlexander V. Chernikov #include <net/route.h> 60*9f7d47b0SAlexander V. Chernikov #include <net/vnet.h> 61*9f7d47b0SAlexander V. Chernikov 62*9f7d47b0SAlexander V. Chernikov #include <netinet/in.h> 63*9f7d47b0SAlexander V. Chernikov #include <netinet/ip_var.h> /* struct ipfw_rule_ref */ 64*9f7d47b0SAlexander V. Chernikov #include <netinet/ip_fw.h> 65*9f7d47b0SAlexander V. Chernikov 66*9f7d47b0SAlexander V. Chernikov #include <netpfil/ipfw/ip_fw_private.h> 67*9f7d47b0SAlexander V. Chernikov 68*9f7d47b0SAlexander V. Chernikov static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 69*9f7d47b0SAlexander V. Chernikov 70*9f7d47b0SAlexander V. Chernikov /* 71*9f7d47b0SAlexander V. Chernikov * The radix code expects addr and mask to be array of bytes, 72*9f7d47b0SAlexander V. Chernikov * with the first byte being the length of the array. rn_inithead 73*9f7d47b0SAlexander V. Chernikov * is called with the offset in bits of the lookup key within the 74*9f7d47b0SAlexander V. Chernikov * array. If we use a sockaddr_in as the underlying type, 75*9f7d47b0SAlexander V. Chernikov * sin_len is conveniently located at offset 0, sin_addr is at 76*9f7d47b0SAlexander V. Chernikov * offset 4 and normally aligned. 77*9f7d47b0SAlexander V. Chernikov * But for portability, let's avoid assumption and make the code explicit 78*9f7d47b0SAlexander V. Chernikov */ 79*9f7d47b0SAlexander V. Chernikov #define KEY_LEN(v) *((uint8_t *)&(v)) 80*9f7d47b0SAlexander V. Chernikov #define KEY_OFS (8*offsetof(struct sockaddr_in, sin_addr)) 81*9f7d47b0SAlexander V. Chernikov /* 82*9f7d47b0SAlexander V. Chernikov * Do not require radix to compare more than actual IPv4/IPv6 address 83*9f7d47b0SAlexander V. Chernikov */ 84*9f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t)) 85*9f7d47b0SAlexander V. Chernikov #define KEY_LEN_INET6 (offsetof(struct sockaddr_in6, sin6_addr) + sizeof(struct in6_addr)) 86*9f7d47b0SAlexander V. Chernikov #define KEY_LEN_IFACE (offsetof(struct xaddr_iface, ifname)) 87*9f7d47b0SAlexander V. Chernikov 88*9f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr)) 89*9f7d47b0SAlexander V. Chernikov #define OFF_LEN_INET6 (8 * offsetof(struct sockaddr_in6, sin6_addr)) 90*9f7d47b0SAlexander V. Chernikov #define OFF_LEN_IFACE (8 * offsetof(struct xaddr_iface, ifname)) 91*9f7d47b0SAlexander V. Chernikov 92*9f7d47b0SAlexander V. Chernikov struct table_entry { 93*9f7d47b0SAlexander V. Chernikov struct radix_node rn[2]; 94*9f7d47b0SAlexander V. Chernikov struct sockaddr_in addr, mask; 95*9f7d47b0SAlexander V. Chernikov u_int32_t value; 96*9f7d47b0SAlexander V. Chernikov }; 97*9f7d47b0SAlexander V. Chernikov 98*9f7d47b0SAlexander V. Chernikov struct xaddr_iface { 99*9f7d47b0SAlexander V. Chernikov uint8_t if_len; /* length of this struct */ 100*9f7d47b0SAlexander V. Chernikov uint8_t pad[7]; /* Align name */ 101*9f7d47b0SAlexander V. Chernikov char ifname[IF_NAMESIZE]; /* Interface name */ 102*9f7d47b0SAlexander V. Chernikov }; 103*9f7d47b0SAlexander V. Chernikov 104*9f7d47b0SAlexander V. Chernikov struct table_xentry { 105*9f7d47b0SAlexander V. Chernikov struct radix_node rn[2]; 106*9f7d47b0SAlexander V. Chernikov union { 107*9f7d47b0SAlexander V. Chernikov #ifdef INET6 108*9f7d47b0SAlexander V. Chernikov struct sockaddr_in6 addr6; 109*9f7d47b0SAlexander V. Chernikov #endif 110*9f7d47b0SAlexander V. Chernikov struct xaddr_iface iface; 111*9f7d47b0SAlexander V. Chernikov } a; 112*9f7d47b0SAlexander V. Chernikov union { 113*9f7d47b0SAlexander V. Chernikov #ifdef INET6 114*9f7d47b0SAlexander V. Chernikov struct sockaddr_in6 mask6; 115*9f7d47b0SAlexander V. Chernikov #endif 116*9f7d47b0SAlexander V. Chernikov struct xaddr_iface ifmask; 117*9f7d47b0SAlexander V. Chernikov } m; 118*9f7d47b0SAlexander V. Chernikov u_int32_t value; 119*9f7d47b0SAlexander V. Chernikov }; 120*9f7d47b0SAlexander V. Chernikov 121*9f7d47b0SAlexander V. Chernikov 122*9f7d47b0SAlexander V. Chernikov 123*9f7d47b0SAlexander V. Chernikov 124*9f7d47b0SAlexander V. Chernikov /* 125*9f7d47b0SAlexander V. Chernikov * CIDR implementation using radix 126*9f7d47b0SAlexander V. Chernikov * 127*9f7d47b0SAlexander V. Chernikov */ 128*9f7d47b0SAlexander V. Chernikov 129*9f7d47b0SAlexander V. Chernikov static int 130*9f7d47b0SAlexander V. Chernikov ta_lookup_radix(struct table_info *ti, void *key, uint32_t keylen, 131*9f7d47b0SAlexander V. Chernikov uint32_t *val) 132*9f7d47b0SAlexander V. Chernikov { 133*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 134*9f7d47b0SAlexander V. Chernikov 135*9f7d47b0SAlexander V. Chernikov if (keylen == sizeof(in_addr_t)) { 136*9f7d47b0SAlexander V. Chernikov struct table_entry *ent; 137*9f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 138*9f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 139*9f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = *((in_addr_t *)key); 140*9f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->state; 141*9f7d47b0SAlexander V. Chernikov ent = (struct table_entry *)(rnh->rnh_matchaddr(&sa, rnh)); 142*9f7d47b0SAlexander V. Chernikov if (ent != NULL) { 143*9f7d47b0SAlexander V. Chernikov *val = ent->value; 144*9f7d47b0SAlexander V. Chernikov return (1); 145*9f7d47b0SAlexander V. Chernikov } 146*9f7d47b0SAlexander V. Chernikov } else { 147*9f7d47b0SAlexander V. Chernikov struct table_xentry *xent; 148*9f7d47b0SAlexander V. Chernikov struct sockaddr_in6 sa6; 149*9f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 150*9f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, key, sizeof(struct in6_addr)); 151*9f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 152*9f7d47b0SAlexander V. Chernikov xent = (struct table_xentry *)(rnh->rnh_matchaddr(&sa6, rnh)); 153*9f7d47b0SAlexander V. Chernikov if (xent != NULL) { 154*9f7d47b0SAlexander V. Chernikov *val = xent->value; 155*9f7d47b0SAlexander V. Chernikov return (1); 156*9f7d47b0SAlexander V. Chernikov } 157*9f7d47b0SAlexander V. Chernikov } 158*9f7d47b0SAlexander V. Chernikov 159*9f7d47b0SAlexander V. Chernikov return (0); 160*9f7d47b0SAlexander V. Chernikov } 161*9f7d47b0SAlexander V. Chernikov 162*9f7d47b0SAlexander V. Chernikov /* 163*9f7d47b0SAlexander V. Chernikov * New table 164*9f7d47b0SAlexander V. Chernikov */ 165*9f7d47b0SAlexander V. Chernikov static int 166*9f7d47b0SAlexander V. Chernikov ta_init_radix(void **ta_state, struct table_info *ti) 167*9f7d47b0SAlexander V. Chernikov { 168*9f7d47b0SAlexander V. Chernikov 169*9f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->state, OFF_LEN_INET)) 170*9f7d47b0SAlexander V. Chernikov return (ENOMEM); 171*9f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_INET6)) { 172*9f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 173*9f7d47b0SAlexander V. Chernikov return (ENOMEM); 174*9f7d47b0SAlexander V. Chernikov } 175*9f7d47b0SAlexander V. Chernikov 176*9f7d47b0SAlexander V. Chernikov *ta_state = NULL; 177*9f7d47b0SAlexander V. Chernikov ti->lookup = ta_lookup_radix; 178*9f7d47b0SAlexander V. Chernikov 179*9f7d47b0SAlexander V. Chernikov return (0); 180*9f7d47b0SAlexander V. Chernikov } 181*9f7d47b0SAlexander V. Chernikov 182*9f7d47b0SAlexander V. Chernikov static int 183*9f7d47b0SAlexander V. Chernikov flush_table_entry(struct radix_node *rn, void *arg) 184*9f7d47b0SAlexander V. Chernikov { 185*9f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 186*9f7d47b0SAlexander V. Chernikov struct table_entry *ent; 187*9f7d47b0SAlexander V. Chernikov 188*9f7d47b0SAlexander V. Chernikov ent = (struct table_entry *) 189*9f7d47b0SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 190*9f7d47b0SAlexander V. Chernikov if (ent != NULL) 191*9f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 192*9f7d47b0SAlexander V. Chernikov return (0); 193*9f7d47b0SAlexander V. Chernikov } 194*9f7d47b0SAlexander V. Chernikov 195*9f7d47b0SAlexander V. Chernikov static void 196*9f7d47b0SAlexander V. Chernikov ta_destroy_radix(void *ta_state, struct table_info *ti) 197*9f7d47b0SAlexander V. Chernikov { 198*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 199*9f7d47b0SAlexander V. Chernikov 200*9f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 201*9f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_table_entry, rnh); 202*9f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 203*9f7d47b0SAlexander V. Chernikov 204*9f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 205*9f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_table_entry, rnh); 206*9f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->xstate); 207*9f7d47b0SAlexander V. Chernikov } 208*9f7d47b0SAlexander V. Chernikov 209*9f7d47b0SAlexander V. Chernikov static int 210*9f7d47b0SAlexander V. Chernikov ta_dump_radix_entry(void *ta_state, struct table_info *ti, void *e, 211*9f7d47b0SAlexander V. Chernikov ipfw_table_entry *ent) 212*9f7d47b0SAlexander V. Chernikov { 213*9f7d47b0SAlexander V. Chernikov struct table_entry *n; 214*9f7d47b0SAlexander V. Chernikov 215*9f7d47b0SAlexander V. Chernikov n = (struct table_entry *)e; 216*9f7d47b0SAlexander V. Chernikov 217*9f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 218*9f7d47b0SAlexander V. Chernikov if (n->addr.sin_family != AF_INET) 219*9f7d47b0SAlexander V. Chernikov return (0); 220*9f7d47b0SAlexander V. Chernikov 221*9f7d47b0SAlexander V. Chernikov if (in_nullhost(n->mask.sin_addr)) 222*9f7d47b0SAlexander V. Chernikov ent->masklen = 0; 223*9f7d47b0SAlexander V. Chernikov else 224*9f7d47b0SAlexander V. Chernikov ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr)); 225*9f7d47b0SAlexander V. Chernikov ent->addr = n->addr.sin_addr.s_addr; 226*9f7d47b0SAlexander V. Chernikov ent->value = n->value; 227*9f7d47b0SAlexander V. Chernikov 228*9f7d47b0SAlexander V. Chernikov return (0); 229*9f7d47b0SAlexander V. Chernikov } 230*9f7d47b0SAlexander V. Chernikov 231*9f7d47b0SAlexander V. Chernikov static int 232*9f7d47b0SAlexander V. Chernikov ta_dump_radix_xentry(void *ta_state, struct table_info *ti, void *e, 233*9f7d47b0SAlexander V. Chernikov ipfw_table_xentry *xent) 234*9f7d47b0SAlexander V. Chernikov { 235*9f7d47b0SAlexander V. Chernikov struct table_entry *n; 236*9f7d47b0SAlexander V. Chernikov struct table_xentry *xn; 237*9f7d47b0SAlexander V. Chernikov #ifdef INET6 238*9f7d47b0SAlexander V. Chernikov int i; 239*9f7d47b0SAlexander V. Chernikov uint32_t *v; 240*9f7d47b0SAlexander V. Chernikov #endif 241*9f7d47b0SAlexander V. Chernikov 242*9f7d47b0SAlexander V. Chernikov n = (struct table_entry *)e; 243*9f7d47b0SAlexander V. Chernikov 244*9f7d47b0SAlexander V. Chernikov /* Guess IPv4/IPv6 radix by sockaddr family */ 245*9f7d47b0SAlexander V. Chernikov if (n->addr.sin_family == AF_INET) { 246*9f7d47b0SAlexander V. Chernikov if (in_nullhost(n->mask.sin_addr)) 247*9f7d47b0SAlexander V. Chernikov xent->masklen = 0; 248*9f7d47b0SAlexander V. Chernikov else 249*9f7d47b0SAlexander V. Chernikov xent->masklen = 33-ffs(ntohl(n->mask.sin_addr.s_addr)); 250*9f7d47b0SAlexander V. Chernikov /* Save IPv4 address as deprecated IPv6 compatible */ 251*9f7d47b0SAlexander V. Chernikov xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr; 252*9f7d47b0SAlexander V. Chernikov xent->flags = IPFW_TCF_INET; 253*9f7d47b0SAlexander V. Chernikov xent->value = n->value; 254*9f7d47b0SAlexander V. Chernikov #ifdef INET6 255*9f7d47b0SAlexander V. Chernikov } else { 256*9f7d47b0SAlexander V. Chernikov xn = (struct table_xentry *)e; 257*9f7d47b0SAlexander V. Chernikov /* Count IPv6 mask */ 258*9f7d47b0SAlexander V. Chernikov v = (uint32_t *)&xn->m.mask6.sin6_addr; 259*9f7d47b0SAlexander V. Chernikov for (i = 0; i < sizeof(struct in6_addr) / 4; i++, v++) 260*9f7d47b0SAlexander V. Chernikov xent->masklen += bitcount32(*v); 261*9f7d47b0SAlexander V. Chernikov memcpy(&xent->k, &xn->a.addr6.sin6_addr, sizeof(struct in6_addr)); 262*9f7d47b0SAlexander V. Chernikov xent->value = xn->value; 263*9f7d47b0SAlexander V. Chernikov #endif 264*9f7d47b0SAlexander V. Chernikov } 265*9f7d47b0SAlexander V. Chernikov 266*9f7d47b0SAlexander V. Chernikov return (0); 267*9f7d47b0SAlexander V. Chernikov } 268*9f7d47b0SAlexander V. Chernikov 269*9f7d47b0SAlexander V. Chernikov static void 270*9f7d47b0SAlexander V. Chernikov ta_foreach_radix(void *ta_state, struct table_info *ti, ta_foreach_f *f, 271*9f7d47b0SAlexander V. Chernikov void *arg) 272*9f7d47b0SAlexander V. Chernikov { 273*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 274*9f7d47b0SAlexander V. Chernikov 275*9f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->state); 276*9f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 277*9f7d47b0SAlexander V. Chernikov 278*9f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 279*9f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 280*9f7d47b0SAlexander V. Chernikov } 281*9f7d47b0SAlexander V. Chernikov 282*9f7d47b0SAlexander V. Chernikov 283*9f7d47b0SAlexander V. Chernikov struct ta_buf_cidr 284*9f7d47b0SAlexander V. Chernikov { 285*9f7d47b0SAlexander V. Chernikov struct sockaddr *addr_ptr; 286*9f7d47b0SAlexander V. Chernikov struct sockaddr *mask_ptr; 287*9f7d47b0SAlexander V. Chernikov void *ent_ptr; 288*9f7d47b0SAlexander V. Chernikov union { 289*9f7d47b0SAlexander V. Chernikov struct { 290*9f7d47b0SAlexander V. Chernikov struct sockaddr_in sa; 291*9f7d47b0SAlexander V. Chernikov struct sockaddr_in ma; 292*9f7d47b0SAlexander V. Chernikov } a4; 293*9f7d47b0SAlexander V. Chernikov struct { 294*9f7d47b0SAlexander V. Chernikov struct sockaddr_in6 sa; 295*9f7d47b0SAlexander V. Chernikov struct sockaddr_in6 ma; 296*9f7d47b0SAlexander V. Chernikov } a6; 297*9f7d47b0SAlexander V. Chernikov } addr; 298*9f7d47b0SAlexander V. Chernikov }; 299*9f7d47b0SAlexander V. Chernikov 300*9f7d47b0SAlexander V. Chernikov #ifdef INET6 301*9f7d47b0SAlexander V. Chernikov static inline void 302*9f7d47b0SAlexander V. Chernikov ipv6_writemask(struct in6_addr *addr6, uint8_t mask) 303*9f7d47b0SAlexander V. Chernikov { 304*9f7d47b0SAlexander V. Chernikov uint32_t *cp; 305*9f7d47b0SAlexander V. Chernikov 306*9f7d47b0SAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 307*9f7d47b0SAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 308*9f7d47b0SAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 309*9f7d47b0SAlexander V. Chernikov } 310*9f7d47b0SAlexander V. Chernikov #endif 311*9f7d47b0SAlexander V. Chernikov 312*9f7d47b0SAlexander V. Chernikov 313*9f7d47b0SAlexander V. Chernikov static int 314*9f7d47b0SAlexander V. Chernikov ta_prepare_add_cidr(struct tentry_info *tei, void *ta_buf) 315*9f7d47b0SAlexander V. Chernikov { 316*9f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 317*9f7d47b0SAlexander V. Chernikov struct table_entry *ent; 318*9f7d47b0SAlexander V. Chernikov struct table_xentry *xent; 319*9f7d47b0SAlexander V. Chernikov in_addr_t addr; 320*9f7d47b0SAlexander V. Chernikov int mlen; 321*9f7d47b0SAlexander V. Chernikov 322*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 323*9f7d47b0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 324*9f7d47b0SAlexander V. Chernikov 325*9f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 326*9f7d47b0SAlexander V. Chernikov 327*9f7d47b0SAlexander V. Chernikov if (tei->plen == sizeof(in_addr_t)) { 328*9f7d47b0SAlexander V. Chernikov #ifdef INET 329*9f7d47b0SAlexander V. Chernikov /* IPv4 case */ 330*9f7d47b0SAlexander V. Chernikov if (mlen > 32) 331*9f7d47b0SAlexander V. Chernikov return (EINVAL); 332*9f7d47b0SAlexander V. Chernikov ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO); 333*9f7d47b0SAlexander V. Chernikov ent->value = tei->value; 334*9f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 335*9f7d47b0SAlexander V. Chernikov KEY_LEN(ent->addr) = KEY_LEN_INET; 336*9f7d47b0SAlexander V. Chernikov KEY_LEN(ent->mask) = KEY_LEN_INET; 337*9f7d47b0SAlexander V. Chernikov ent->addr.sin_family = AF_INET; 338*9f7d47b0SAlexander V. Chernikov ent->mask.sin_addr.s_addr = 339*9f7d47b0SAlexander V. Chernikov htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 340*9f7d47b0SAlexander V. Chernikov addr = *((in_addr_t *)tei->paddr); 341*9f7d47b0SAlexander V. Chernikov ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr; 342*9f7d47b0SAlexander V. Chernikov /* Set pointers */ 343*9f7d47b0SAlexander V. Chernikov tb->ent_ptr = ent; 344*9f7d47b0SAlexander V. Chernikov tb->addr_ptr = (struct sockaddr *)&ent->addr; 345*9f7d47b0SAlexander V. Chernikov tb->mask_ptr = (struct sockaddr *)&ent->mask; 346*9f7d47b0SAlexander V. Chernikov #endif 347*9f7d47b0SAlexander V. Chernikov #ifdef INET6 348*9f7d47b0SAlexander V. Chernikov } else if (tei->plen == sizeof(struct in6_addr)) { 349*9f7d47b0SAlexander V. Chernikov /* IPv6 case */ 350*9f7d47b0SAlexander V. Chernikov if (mlen > 128) 351*9f7d47b0SAlexander V. Chernikov return (EINVAL); 352*9f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 353*9f7d47b0SAlexander V. Chernikov xent->value = tei->value; 354*9f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 355*9f7d47b0SAlexander V. Chernikov KEY_LEN(xent->a.addr6) = KEY_LEN_INET6; 356*9f7d47b0SAlexander V. Chernikov KEY_LEN(xent->m.mask6) = KEY_LEN_INET6; 357*9f7d47b0SAlexander V. Chernikov xent->a.addr6.sin6_family = AF_INET6; 358*9f7d47b0SAlexander V. Chernikov ipv6_writemask(&xent->m.mask6.sin6_addr, mlen); 359*9f7d47b0SAlexander V. Chernikov memcpy(&xent->a.addr6.sin6_addr, tei->paddr, 360*9f7d47b0SAlexander V. Chernikov sizeof(struct in6_addr)); 361*9f7d47b0SAlexander V. Chernikov APPLY_MASK(&xent->a.addr6.sin6_addr, &xent->m.mask6.sin6_addr); 362*9f7d47b0SAlexander V. Chernikov /* Set pointers */ 363*9f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 364*9f7d47b0SAlexander V. Chernikov tb->addr_ptr = (struct sockaddr *)&xent->a.addr6; 365*9f7d47b0SAlexander V. Chernikov tb->mask_ptr = (struct sockaddr *)&xent->m.mask6; 366*9f7d47b0SAlexander V. Chernikov #endif 367*9f7d47b0SAlexander V. Chernikov } else { 368*9f7d47b0SAlexander V. Chernikov /* Unknown CIDR type */ 369*9f7d47b0SAlexander V. Chernikov return (EINVAL); 370*9f7d47b0SAlexander V. Chernikov } 371*9f7d47b0SAlexander V. Chernikov 372*9f7d47b0SAlexander V. Chernikov return (0); 373*9f7d47b0SAlexander V. Chernikov } 374*9f7d47b0SAlexander V. Chernikov 375*9f7d47b0SAlexander V. Chernikov static int 376*9f7d47b0SAlexander V. Chernikov ta_add_cidr(void *ta_state, struct table_info *ti, 377*9f7d47b0SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf) 378*9f7d47b0SAlexander V. Chernikov { 379*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 380*9f7d47b0SAlexander V. Chernikov struct radix_node *rn; 381*9f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 382*9f7d47b0SAlexander V. Chernikov 383*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 384*9f7d47b0SAlexander V. Chernikov 385*9f7d47b0SAlexander V. Chernikov if (tei->plen == sizeof(in_addr_t)) 386*9f7d47b0SAlexander V. Chernikov rnh = ti->state; 387*9f7d47b0SAlexander V. Chernikov else 388*9f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 389*9f7d47b0SAlexander V. Chernikov 390*9f7d47b0SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr); 391*9f7d47b0SAlexander V. Chernikov 392*9f7d47b0SAlexander V. Chernikov if (rn == NULL) 393*9f7d47b0SAlexander V. Chernikov return (EEXIST); 394*9f7d47b0SAlexander V. Chernikov 395*9f7d47b0SAlexander V. Chernikov return (0); 396*9f7d47b0SAlexander V. Chernikov } 397*9f7d47b0SAlexander V. Chernikov 398*9f7d47b0SAlexander V. Chernikov static int 399*9f7d47b0SAlexander V. Chernikov ta_prepare_del_cidr(struct tentry_info *tei, void *ta_buf) 400*9f7d47b0SAlexander V. Chernikov { 401*9f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 402*9f7d47b0SAlexander V. Chernikov in_addr_t addr; 403*9f7d47b0SAlexander V. Chernikov int mlen; 404*9f7d47b0SAlexander V. Chernikov 405*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 406*9f7d47b0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 407*9f7d47b0SAlexander V. Chernikov 408*9f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 409*9f7d47b0SAlexander V. Chernikov 410*9f7d47b0SAlexander V. Chernikov if (tei->plen == sizeof(in_addr_t)) { 411*9f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 412*9f7d47b0SAlexander V. Chernikov struct sockaddr_in sa, mask; 413*9f7d47b0SAlexander V. Chernikov KEY_LEN(sa) = KEY_LEN_INET; 414*9f7d47b0SAlexander V. Chernikov KEY_LEN(mask) = KEY_LEN_INET; 415*9f7d47b0SAlexander V. Chernikov mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 416*9f7d47b0SAlexander V. Chernikov addr = *((in_addr_t *)tei->paddr); 417*9f7d47b0SAlexander V. Chernikov sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 418*9f7d47b0SAlexander V. Chernikov tb->addr.a4.sa = sa; 419*9f7d47b0SAlexander V. Chernikov tb->addr.a4.ma = mask; 420*9f7d47b0SAlexander V. Chernikov tb->addr_ptr = (struct sockaddr *)&tb->addr.a4.sa; 421*9f7d47b0SAlexander V. Chernikov tb->mask_ptr = (struct sockaddr *)&tb->addr.a4.ma; 422*9f7d47b0SAlexander V. Chernikov #ifdef INET6 423*9f7d47b0SAlexander V. Chernikov } else if (tei->plen == sizeof(struct in6_addr)) { 424*9f7d47b0SAlexander V. Chernikov /* IPv6 case */ 425*9f7d47b0SAlexander V. Chernikov if (mlen > 128) 426*9f7d47b0SAlexander V. Chernikov return (EINVAL); 427*9f7d47b0SAlexander V. Chernikov struct sockaddr_in6 sa6, mask6; 428*9f7d47b0SAlexander V. Chernikov memset(&sa6, 0, sizeof(struct sockaddr_in6)); 429*9f7d47b0SAlexander V. Chernikov memset(&mask6, 0, sizeof(struct sockaddr_in6)); 430*9f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 431*9f7d47b0SAlexander V. Chernikov KEY_LEN(sa6) = KEY_LEN_INET6; 432*9f7d47b0SAlexander V. Chernikov KEY_LEN(mask6) = KEY_LEN_INET6; 433*9f7d47b0SAlexander V. Chernikov ipv6_writemask(&mask6.sin6_addr, mlen); 434*9f7d47b0SAlexander V. Chernikov memcpy(&sa6.sin6_addr, tei->paddr, 435*9f7d47b0SAlexander V. Chernikov sizeof(struct in6_addr)); 436*9f7d47b0SAlexander V. Chernikov APPLY_MASK(&sa6.sin6_addr, &mask6.sin6_addr); 437*9f7d47b0SAlexander V. Chernikov tb->addr.a6.sa = sa6; 438*9f7d47b0SAlexander V. Chernikov tb->addr.a6.ma = mask6; 439*9f7d47b0SAlexander V. Chernikov tb->addr_ptr = (struct sockaddr *)&tb->addr.a6.sa; 440*9f7d47b0SAlexander V. Chernikov tb->mask_ptr = (struct sockaddr *)&tb->addr.a6.ma; 441*9f7d47b0SAlexander V. Chernikov #endif 442*9f7d47b0SAlexander V. Chernikov } else 443*9f7d47b0SAlexander V. Chernikov return (EINVAL); 444*9f7d47b0SAlexander V. Chernikov 445*9f7d47b0SAlexander V. Chernikov return (0); 446*9f7d47b0SAlexander V. Chernikov } 447*9f7d47b0SAlexander V. Chernikov 448*9f7d47b0SAlexander V. Chernikov static int 449*9f7d47b0SAlexander V. Chernikov ta_del_cidr(void *ta_state, struct table_info *ti, 450*9f7d47b0SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf) 451*9f7d47b0SAlexander V. Chernikov { 452*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 453*9f7d47b0SAlexander V. Chernikov struct radix_node *rn; 454*9f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 455*9f7d47b0SAlexander V. Chernikov 456*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 457*9f7d47b0SAlexander V. Chernikov 458*9f7d47b0SAlexander V. Chernikov if (tei->plen == sizeof(in_addr_t)) 459*9f7d47b0SAlexander V. Chernikov rnh = ti->state; 460*9f7d47b0SAlexander V. Chernikov else 461*9f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 462*9f7d47b0SAlexander V. Chernikov 463*9f7d47b0SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh); 464*9f7d47b0SAlexander V. Chernikov 465*9f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 466*9f7d47b0SAlexander V. Chernikov 467*9f7d47b0SAlexander V. Chernikov if (rn == NULL) 468*9f7d47b0SAlexander V. Chernikov return (ESRCH); 469*9f7d47b0SAlexander V. Chernikov 470*9f7d47b0SAlexander V. Chernikov return (0); 471*9f7d47b0SAlexander V. Chernikov } 472*9f7d47b0SAlexander V. Chernikov 473*9f7d47b0SAlexander V. Chernikov static void 474*9f7d47b0SAlexander V. Chernikov ta_flush_cidr_entry(struct tentry_info *tei, void *ta_buf) 475*9f7d47b0SAlexander V. Chernikov { 476*9f7d47b0SAlexander V. Chernikov struct ta_buf_cidr *tb; 477*9f7d47b0SAlexander V. Chernikov 478*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_cidr *)ta_buf; 479*9f7d47b0SAlexander V. Chernikov 480*9f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 481*9f7d47b0SAlexander V. Chernikov } 482*9f7d47b0SAlexander V. Chernikov 483*9f7d47b0SAlexander V. Chernikov struct table_algo radix_cidr = { 484*9f7d47b0SAlexander V. Chernikov .name = "cidr", 485*9f7d47b0SAlexander V. Chernikov .lookup = ta_lookup_radix, 486*9f7d47b0SAlexander V. Chernikov .init = ta_init_radix, 487*9f7d47b0SAlexander V. Chernikov .destroy = ta_destroy_radix, 488*9f7d47b0SAlexander V. Chernikov .prepare_add = ta_prepare_add_cidr, 489*9f7d47b0SAlexander V. Chernikov .prepare_del = ta_prepare_del_cidr, 490*9f7d47b0SAlexander V. Chernikov .add = ta_add_cidr, 491*9f7d47b0SAlexander V. Chernikov .del = ta_del_cidr, 492*9f7d47b0SAlexander V. Chernikov .flush_entry = ta_flush_cidr_entry, 493*9f7d47b0SAlexander V. Chernikov .foreach = ta_foreach_radix, 494*9f7d47b0SAlexander V. Chernikov .dump_entry = ta_dump_radix_entry, 495*9f7d47b0SAlexander V. Chernikov .dump_xentry = ta_dump_radix_xentry, 496*9f7d47b0SAlexander V. Chernikov }; 497*9f7d47b0SAlexander V. Chernikov 498*9f7d47b0SAlexander V. Chernikov 499*9f7d47b0SAlexander V. Chernikov /* 500*9f7d47b0SAlexander V. Chernikov * Iface table cmds 501*9f7d47b0SAlexander V. Chernikov * 502*9f7d47b0SAlexander V. Chernikov */ 503*9f7d47b0SAlexander V. Chernikov 504*9f7d47b0SAlexander V. Chernikov static int 505*9f7d47b0SAlexander V. Chernikov ta_lookup_iface(struct table_info *ti, void *key, uint32_t keylen, 506*9f7d47b0SAlexander V. Chernikov uint32_t *val) 507*9f7d47b0SAlexander V. Chernikov { 508*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 509*9f7d47b0SAlexander V. Chernikov struct xaddr_iface iface; 510*9f7d47b0SAlexander V. Chernikov struct table_xentry *xent; 511*9f7d47b0SAlexander V. Chernikov 512*9f7d47b0SAlexander V. Chernikov KEY_LEN(iface) = KEY_LEN_IFACE + 513*9f7d47b0SAlexander V. Chernikov strlcpy(iface.ifname, (char *)key, IF_NAMESIZE) + 1; 514*9f7d47b0SAlexander V. Chernikov 515*9f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)ti->xstate; 516*9f7d47b0SAlexander V. Chernikov xent = (struct table_xentry *)(rnh->rnh_matchaddr(&iface, rnh)); 517*9f7d47b0SAlexander V. Chernikov if (xent != NULL) { 518*9f7d47b0SAlexander V. Chernikov *val = xent->value; 519*9f7d47b0SAlexander V. Chernikov return (1); 520*9f7d47b0SAlexander V. Chernikov } 521*9f7d47b0SAlexander V. Chernikov 522*9f7d47b0SAlexander V. Chernikov return (0); 523*9f7d47b0SAlexander V. Chernikov } 524*9f7d47b0SAlexander V. Chernikov 525*9f7d47b0SAlexander V. Chernikov static int 526*9f7d47b0SAlexander V. Chernikov flush_iface_entry(struct radix_node *rn, void *arg) 527*9f7d47b0SAlexander V. Chernikov { 528*9f7d47b0SAlexander V. Chernikov struct radix_node_head * const rnh = arg; 529*9f7d47b0SAlexander V. Chernikov struct table_entry *ent; 530*9f7d47b0SAlexander V. Chernikov 531*9f7d47b0SAlexander V. Chernikov ent = (struct table_entry *) 532*9f7d47b0SAlexander V. Chernikov rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 533*9f7d47b0SAlexander V. Chernikov if (ent != NULL) 534*9f7d47b0SAlexander V. Chernikov free(ent, M_IPFW_TBL); 535*9f7d47b0SAlexander V. Chernikov return (0); 536*9f7d47b0SAlexander V. Chernikov } 537*9f7d47b0SAlexander V. Chernikov 538*9f7d47b0SAlexander V. Chernikov static int 539*9f7d47b0SAlexander V. Chernikov ta_init_iface(void **ta_state, struct table_info *ti) 540*9f7d47b0SAlexander V. Chernikov { 541*9f7d47b0SAlexander V. Chernikov 542*9f7d47b0SAlexander V. Chernikov if (!rn_inithead(&ti->xstate, OFF_LEN_IFACE)) 543*9f7d47b0SAlexander V. Chernikov return (ENOMEM); 544*9f7d47b0SAlexander V. Chernikov 545*9f7d47b0SAlexander V. Chernikov *ta_state = NULL; 546*9f7d47b0SAlexander V. Chernikov ti->lookup = ta_lookup_iface; 547*9f7d47b0SAlexander V. Chernikov 548*9f7d47b0SAlexander V. Chernikov return (0); 549*9f7d47b0SAlexander V. Chernikov } 550*9f7d47b0SAlexander V. Chernikov 551*9f7d47b0SAlexander V. Chernikov 552*9f7d47b0SAlexander V. Chernikov static void 553*9f7d47b0SAlexander V. Chernikov ta_destroy_iface(void *ta_state, struct table_info *ti) 554*9f7d47b0SAlexander V. Chernikov { 555*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 556*9f7d47b0SAlexander V. Chernikov 557*9f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 558*9f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, flush_iface_entry, rnh); 559*9f7d47b0SAlexander V. Chernikov rn_detachhead(&ti->state); 560*9f7d47b0SAlexander V. Chernikov } 561*9f7d47b0SAlexander V. Chernikov 562*9f7d47b0SAlexander V. Chernikov struct ta_buf_iface 563*9f7d47b0SAlexander V. Chernikov { 564*9f7d47b0SAlexander V. Chernikov void *addr_ptr; 565*9f7d47b0SAlexander V. Chernikov void *mask_ptr; 566*9f7d47b0SAlexander V. Chernikov void *ent_ptr; 567*9f7d47b0SAlexander V. Chernikov struct xaddr_iface iface; 568*9f7d47b0SAlexander V. Chernikov }; 569*9f7d47b0SAlexander V. Chernikov 570*9f7d47b0SAlexander V. Chernikov static int 571*9f7d47b0SAlexander V. Chernikov ta_prepare_add_iface(struct tentry_info *tei, void *ta_buf) 572*9f7d47b0SAlexander V. Chernikov { 573*9f7d47b0SAlexander V. Chernikov struct ta_buf_iface *tb; 574*9f7d47b0SAlexander V. Chernikov struct table_xentry *xent; 575*9f7d47b0SAlexander V. Chernikov int mlen; 576*9f7d47b0SAlexander V. Chernikov char c; 577*9f7d47b0SAlexander V. Chernikov 578*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_iface *)ta_buf; 579*9f7d47b0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 580*9f7d47b0SAlexander V. Chernikov 581*9f7d47b0SAlexander V. Chernikov mlen = tei->masklen; 582*9f7d47b0SAlexander V. Chernikov 583*9f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 584*9f7d47b0SAlexander V. Chernikov c = ((char *)tei->paddr)[IF_NAMESIZE - 1]; 585*9f7d47b0SAlexander V. Chernikov ((char *)tei->paddr)[IF_NAMESIZE - 1] = '\0'; 586*9f7d47b0SAlexander V. Chernikov mlen = strlen((char *)tei->paddr); 587*9f7d47b0SAlexander V. Chernikov if ((mlen == IF_NAMESIZE - 1) && (c != '\0')) 588*9f7d47b0SAlexander V. Chernikov return (EINVAL); 589*9f7d47b0SAlexander V. Chernikov 590*9f7d47b0SAlexander V. Chernikov /* Include last \0 into comparison */ 591*9f7d47b0SAlexander V. Chernikov mlen++; 592*9f7d47b0SAlexander V. Chernikov 593*9f7d47b0SAlexander V. Chernikov xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO); 594*9f7d47b0SAlexander V. Chernikov xent->value = tei->value; 595*9f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 596*9f7d47b0SAlexander V. Chernikov KEY_LEN(xent->a.iface) = KEY_LEN_IFACE + mlen; 597*9f7d47b0SAlexander V. Chernikov KEY_LEN(xent->m.ifmask) = KEY_LEN_IFACE + mlen; 598*9f7d47b0SAlexander V. Chernikov memcpy(xent->a.iface.ifname, tei->paddr, mlen); 599*9f7d47b0SAlexander V. Chernikov /* Set pointers */ 600*9f7d47b0SAlexander V. Chernikov tb->ent_ptr = xent; 601*9f7d47b0SAlexander V. Chernikov tb->addr_ptr = (struct sockaddr *)&xent->a.iface; 602*9f7d47b0SAlexander V. Chernikov /* Assume direct match */ 603*9f7d47b0SAlexander V. Chernikov tb->mask_ptr = NULL; 604*9f7d47b0SAlexander V. Chernikov 605*9f7d47b0SAlexander V. Chernikov return (0); 606*9f7d47b0SAlexander V. Chernikov } 607*9f7d47b0SAlexander V. Chernikov 608*9f7d47b0SAlexander V. Chernikov static int 609*9f7d47b0SAlexander V. Chernikov ta_add_iface(void *ta_state, struct table_info *ti, 610*9f7d47b0SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf) 611*9f7d47b0SAlexander V. Chernikov { 612*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 613*9f7d47b0SAlexander V. Chernikov struct radix_node *rn; 614*9f7d47b0SAlexander V. Chernikov struct ta_buf_iface *tb; 615*9f7d47b0SAlexander V. Chernikov 616*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_iface *)ta_buf; 617*9f7d47b0SAlexander V. Chernikov 618*9f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 619*9f7d47b0SAlexander V. Chernikov rn = rnh->rnh_addaddr(tb->addr_ptr, tb->mask_ptr, rnh, tb->ent_ptr); 620*9f7d47b0SAlexander V. Chernikov 621*9f7d47b0SAlexander V. Chernikov if (rn == NULL) 622*9f7d47b0SAlexander V. Chernikov return (1); 623*9f7d47b0SAlexander V. Chernikov 624*9f7d47b0SAlexander V. Chernikov return (0); 625*9f7d47b0SAlexander V. Chernikov } 626*9f7d47b0SAlexander V. Chernikov 627*9f7d47b0SAlexander V. Chernikov static int 628*9f7d47b0SAlexander V. Chernikov ta_prepare_del_iface(struct tentry_info *tei, void *ta_buf) 629*9f7d47b0SAlexander V. Chernikov { 630*9f7d47b0SAlexander V. Chernikov struct ta_buf_iface *tb; 631*9f7d47b0SAlexander V. Chernikov int mlen; 632*9f7d47b0SAlexander V. Chernikov char c; 633*9f7d47b0SAlexander V. Chernikov 634*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_iface *)ta_buf; 635*9f7d47b0SAlexander V. Chernikov memset(tb, 0, sizeof(struct ta_buf_cidr)); 636*9f7d47b0SAlexander V. Chernikov 637*9f7d47b0SAlexander V. Chernikov /* Check if string is terminated */ 638*9f7d47b0SAlexander V. Chernikov c = ((char *)tei->paddr)[IF_NAMESIZE - 1]; 639*9f7d47b0SAlexander V. Chernikov ((char *)tei->paddr)[IF_NAMESIZE - 1] = '\0'; 640*9f7d47b0SAlexander V. Chernikov mlen = strlen((char *)tei->paddr); 641*9f7d47b0SAlexander V. Chernikov if ((mlen == IF_NAMESIZE - 1) && (c != '\0')) 642*9f7d47b0SAlexander V. Chernikov return (EINVAL); 643*9f7d47b0SAlexander V. Chernikov 644*9f7d47b0SAlexander V. Chernikov struct xaddr_iface ifname, ifmask; 645*9f7d47b0SAlexander V. Chernikov memset(&ifname, 0, sizeof(ifname)); 646*9f7d47b0SAlexander V. Chernikov 647*9f7d47b0SAlexander V. Chernikov /* Include last \0 into comparison */ 648*9f7d47b0SAlexander V. Chernikov mlen++; 649*9f7d47b0SAlexander V. Chernikov 650*9f7d47b0SAlexander V. Chernikov /* Set 'total' structure length */ 651*9f7d47b0SAlexander V. Chernikov KEY_LEN(ifname) = KEY_LEN_IFACE + mlen; 652*9f7d47b0SAlexander V. Chernikov KEY_LEN(ifmask) = KEY_LEN_IFACE + mlen; 653*9f7d47b0SAlexander V. Chernikov /* Assume direct match */ 654*9f7d47b0SAlexander V. Chernikov memcpy(ifname.ifname, tei->paddr, mlen); 655*9f7d47b0SAlexander V. Chernikov /* Set pointers */ 656*9f7d47b0SAlexander V. Chernikov tb->iface = ifname; 657*9f7d47b0SAlexander V. Chernikov tb->addr_ptr = &tb->iface; 658*9f7d47b0SAlexander V. Chernikov tb->mask_ptr = NULL; 659*9f7d47b0SAlexander V. Chernikov 660*9f7d47b0SAlexander V. Chernikov return (0); 661*9f7d47b0SAlexander V. Chernikov } 662*9f7d47b0SAlexander V. Chernikov 663*9f7d47b0SAlexander V. Chernikov static int 664*9f7d47b0SAlexander V. Chernikov ta_del_iface(void *ta_state, struct table_info *ti, 665*9f7d47b0SAlexander V. Chernikov struct tentry_info *tei, void *ta_buf) 666*9f7d47b0SAlexander V. Chernikov { 667*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 668*9f7d47b0SAlexander V. Chernikov struct radix_node *rn; 669*9f7d47b0SAlexander V. Chernikov struct ta_buf_iface *tb; 670*9f7d47b0SAlexander V. Chernikov 671*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_iface *)ta_buf; 672*9f7d47b0SAlexander V. Chernikov 673*9f7d47b0SAlexander V. Chernikov rnh = ti->xstate; 674*9f7d47b0SAlexander V. Chernikov rn = rnh->rnh_deladdr(tb->addr_ptr, tb->mask_ptr, rnh); 675*9f7d47b0SAlexander V. Chernikov 676*9f7d47b0SAlexander V. Chernikov tb->ent_ptr = rn; 677*9f7d47b0SAlexander V. Chernikov 678*9f7d47b0SAlexander V. Chernikov if (rn == NULL) 679*9f7d47b0SAlexander V. Chernikov return (ESRCH); 680*9f7d47b0SAlexander V. Chernikov 681*9f7d47b0SAlexander V. Chernikov return (0); 682*9f7d47b0SAlexander V. Chernikov } 683*9f7d47b0SAlexander V. Chernikov 684*9f7d47b0SAlexander V. Chernikov static void 685*9f7d47b0SAlexander V. Chernikov ta_flush_iface_entry(struct tentry_info *tei, void *ta_buf) 686*9f7d47b0SAlexander V. Chernikov { 687*9f7d47b0SAlexander V. Chernikov struct ta_buf_iface *tb; 688*9f7d47b0SAlexander V. Chernikov 689*9f7d47b0SAlexander V. Chernikov tb = (struct ta_buf_iface *)ta_buf; 690*9f7d47b0SAlexander V. Chernikov 691*9f7d47b0SAlexander V. Chernikov free(tb->ent_ptr, M_IPFW_TBL); 692*9f7d47b0SAlexander V. Chernikov } 693*9f7d47b0SAlexander V. Chernikov 694*9f7d47b0SAlexander V. Chernikov static int 695*9f7d47b0SAlexander V. Chernikov ta_dump_iface_xentry(void *ta_state, struct table_info *ti, void *e, 696*9f7d47b0SAlexander V. Chernikov ipfw_table_xentry *xent) 697*9f7d47b0SAlexander V. Chernikov { 698*9f7d47b0SAlexander V. Chernikov struct table_xentry *xn; 699*9f7d47b0SAlexander V. Chernikov 700*9f7d47b0SAlexander V. Chernikov xn = (struct table_xentry *)e; 701*9f7d47b0SAlexander V. Chernikov xent->masklen = 8 * IF_NAMESIZE; 702*9f7d47b0SAlexander V. Chernikov memcpy(&xent->k, &xn->a.iface.ifname, IF_NAMESIZE); 703*9f7d47b0SAlexander V. Chernikov xent->value = xn->value; 704*9f7d47b0SAlexander V. Chernikov 705*9f7d47b0SAlexander V. Chernikov return (0); 706*9f7d47b0SAlexander V. Chernikov } 707*9f7d47b0SAlexander V. Chernikov 708*9f7d47b0SAlexander V. Chernikov static void 709*9f7d47b0SAlexander V. Chernikov ta_foreach_iface(void *ta_state, struct table_info *ti, ta_foreach_f *f, 710*9f7d47b0SAlexander V. Chernikov void *arg) 711*9f7d47b0SAlexander V. Chernikov { 712*9f7d47b0SAlexander V. Chernikov struct radix_node_head *rnh; 713*9f7d47b0SAlexander V. Chernikov 714*9f7d47b0SAlexander V. Chernikov rnh = (struct radix_node_head *)(ti->xstate); 715*9f7d47b0SAlexander V. Chernikov rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); 716*9f7d47b0SAlexander V. Chernikov } 717*9f7d47b0SAlexander V. Chernikov 718*9f7d47b0SAlexander V. Chernikov struct table_algo radix_iface = { 719*9f7d47b0SAlexander V. Chernikov .name = "iface", 720*9f7d47b0SAlexander V. Chernikov .lookup = ta_lookup_iface, 721*9f7d47b0SAlexander V. Chernikov .init = ta_init_iface, 722*9f7d47b0SAlexander V. Chernikov .destroy = ta_destroy_iface, 723*9f7d47b0SAlexander V. Chernikov .prepare_add = ta_prepare_add_iface, 724*9f7d47b0SAlexander V. Chernikov .prepare_del = ta_prepare_del_iface, 725*9f7d47b0SAlexander V. Chernikov .add = ta_add_iface, 726*9f7d47b0SAlexander V. Chernikov .del = ta_del_iface, 727*9f7d47b0SAlexander V. Chernikov .flush_entry = ta_flush_iface_entry, 728*9f7d47b0SAlexander V. Chernikov .foreach = ta_foreach_iface, 729*9f7d47b0SAlexander V. Chernikov .dump_xentry = ta_dump_iface_xentry, 730*9f7d47b0SAlexander V. Chernikov }; 731*9f7d47b0SAlexander V. Chernikov 732*9f7d47b0SAlexander V. Chernikov void 733*9f7d47b0SAlexander V. Chernikov ipfw_table_algo_init(struct ip_fw_chain *chain) 734*9f7d47b0SAlexander V. Chernikov { 735*9f7d47b0SAlexander V. Chernikov /* 736*9f7d47b0SAlexander V. Chernikov * Register all algorithms presented here. 737*9f7d47b0SAlexander V. Chernikov */ 738*9f7d47b0SAlexander V. Chernikov ipfw_add_table_algo(chain, &radix_cidr); 739*9f7d47b0SAlexander V. Chernikov ipfw_add_table_algo(chain, &radix_iface); 740*9f7d47b0SAlexander V. Chernikov } 741*9f7d47b0SAlexander V. Chernikov 742*9f7d47b0SAlexander V. Chernikov void 743*9f7d47b0SAlexander V. Chernikov ipfw_table_algo_destroy(struct ip_fw_chain *chain) 744*9f7d47b0SAlexander V. Chernikov { 745*9f7d47b0SAlexander V. Chernikov /* Do nothing */ 746*9f7d47b0SAlexander V. Chernikov } 747*9f7d47b0SAlexander V. Chernikov 748*9f7d47b0SAlexander V. Chernikov 749