14408d548SBill Yuan /* 24408d548SBill Yuan * Copyright (c) 2015 -2018 The DragonFly Project. All rights reserved. 34408d548SBill Yuan * 44408d548SBill Yuan * This code is derived from software contributed to The DragonFly Project 54408d548SBill Yuan * by Bill Yuan <bycn82@dragonflybsd.org> 64408d548SBill Yuan * 74408d548SBill Yuan * Redistribution and use in source and binary forms, with or without 84408d548SBill Yuan * modification, are permitted provided that the following conditions 94408d548SBill Yuan * are met: 104408d548SBill Yuan * 114408d548SBill Yuan * 1. Redistributions of source code must retain the above copyright 124408d548SBill Yuan * notice, this list of conditions and the following disclaimer. 134408d548SBill Yuan * 2. Redistributions in binary form must reproduce the above copyright 144408d548SBill Yuan * notice, this list of conditions and the following disclaimer in 154408d548SBill Yuan * the documentation and/or other materials provided with the 164408d548SBill Yuan * distribution. 174408d548SBill Yuan * 3. Neither the name of The DragonFly Project nor the names of its 184408d548SBill Yuan * contributors may be used to endorse or promote products derived 194408d548SBill Yuan * from this software without specific, prior written permission. 204408d548SBill Yuan * 214408d548SBill Yuan * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 224408d548SBill Yuan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 234408d548SBill Yuan * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 244408d548SBill Yuan * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 254408d548SBill Yuan * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 264408d548SBill Yuan * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 274408d548SBill Yuan * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 284408d548SBill Yuan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 294408d548SBill Yuan * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 304408d548SBill Yuan * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 314408d548SBill Yuan * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 324408d548SBill Yuan * SUCH DAMAGE. 334408d548SBill Yuan * 344408d548SBill Yuan */ 354408d548SBill Yuan 364408d548SBill Yuan #include <sys/types.h> 374408d548SBill Yuan #include <sys/param.h> 384408d548SBill Yuan #include <sys/systm.h> 394408d548SBill Yuan #include <sys/malloc.h> 404408d548SBill Yuan #include <sys/mbuf.h> 414408d548SBill Yuan #include <sys/kernel.h> 424408d548SBill Yuan #include <sys/proc.h> 434408d548SBill Yuan #include <sys/socket.h> 444408d548SBill Yuan #include <sys/socketvar.h> 454408d548SBill Yuan #include <sys/sysctl.h> 464408d548SBill Yuan #include <sys/syslog.h> 474408d548SBill Yuan #include <sys/ucred.h> 484408d548SBill Yuan #include <sys/in_cksum.h> 494408d548SBill Yuan #include <sys/lock.h> 504408d548SBill Yuan #include <sys/thread2.h> 514408d548SBill Yuan #include <sys/mplock2.h> 524408d548SBill Yuan 53*bff82488SAaron LI #include <net/if.h> 54*bff82488SAaron LI #include <net/route.h> 55*bff82488SAaron LI #include <net/pfil.h> 56*bff82488SAaron LI #include <net/netmsg2.h> 57*bff82488SAaron LI #include <net/ethernet.h> 58*bff82488SAaron LI 594408d548SBill Yuan #include <netinet/in.h> 604408d548SBill Yuan #include <netinet/in_systm.h> 614408d548SBill Yuan #include <netinet/in_var.h> 624408d548SBill Yuan #include <netinet/in_pcb.h> 634408d548SBill Yuan #include <netinet/ip.h> 644408d548SBill Yuan #include <netinet/ip_var.h> 654408d548SBill Yuan #include <netinet/ip_icmp.h> 664408d548SBill Yuan #include <netinet/tcp.h> 674408d548SBill Yuan #include <netinet/tcp_timer.h> 684408d548SBill Yuan #include <netinet/tcp_var.h> 694408d548SBill Yuan #include <netinet/tcpip.h> 704408d548SBill Yuan #include <netinet/udp.h> 714408d548SBill Yuan #include <netinet/udp_var.h> 724408d548SBill Yuan #include <netinet/ip_divert.h> 734408d548SBill Yuan #include <netinet/if_ether.h> 744408d548SBill Yuan 754408d548SBill Yuan #include <net/ipfw3/ip_fw.h> 764408d548SBill Yuan #include <net/ipfw3_basic/ip_fw3_table.h> 774408d548SBill Yuan 784408d548SBill Yuan MALLOC_DEFINE(M_IPFW3_TABLE, "IPFW3_TABLE", "mem for ip_fw3 table"); 794408d548SBill Yuan 804408d548SBill Yuan extern struct ipfw3_context *fw3_ctx[MAXCPU]; 814408d548SBill Yuan 824408d548SBill Yuan /* 834408d548SBill Yuan * activate/create the table by setup the type and reset counts. 844408d548SBill Yuan */ 854408d548SBill Yuan static void 864408d548SBill Yuan table_create_dispatch(netmsg_t nmsg) 874408d548SBill Yuan { 884408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 894408d548SBill Yuan struct ipfw_ioc_table *ioc_table; 904408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 914408d548SBill Yuan struct ipfw3_table_context *table_ctx; 924408d548SBill Yuan ioc_table = tbmsg->ioc_table; 934408d548SBill Yuan int id = ioc_table->id; 944408d548SBill Yuan 954408d548SBill Yuan table_ctx = ctx->table_ctx; 964408d548SBill Yuan table_ctx += id; 974408d548SBill Yuan table_ctx->type = ioc_table->type; 984408d548SBill Yuan table_ctx->count = 0; 994408d548SBill Yuan strlcpy(table_ctx->name , ioc_table->name, IPFW_TABLE_NAME_LEN); 1004408d548SBill Yuan if (table_ctx->type == 1) { 1014408d548SBill Yuan rn_inithead((void **)&table_ctx->mask, NULL, 0); 1024408d548SBill Yuan rn_inithead((void **)&table_ctx->node, table_ctx->mask, 32); 1034408d548SBill Yuan } else if (table_ctx->type == 2) { 1044408d548SBill Yuan rn_inithead((void **)&table_ctx->mask, NULL, 0); 1054408d548SBill Yuan rn_inithead((void **)&table_ctx->node, table_ctx->mask, 48); 1064408d548SBill Yuan } else { 1074408d548SBill Yuan goto done; 1084408d548SBill Yuan } 1094408d548SBill Yuan done: 1104408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 1114408d548SBill Yuan } 1124408d548SBill Yuan 1134408d548SBill Yuan /* 1144408d548SBill Yuan * clean the table, especially the node 1154408d548SBill Yuan */ 1164408d548SBill Yuan static void 1174408d548SBill Yuan table_delete_dispatch(netmsg_t nmsg) 1184408d548SBill Yuan { 1194408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 1204408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl; 1214408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 1224408d548SBill Yuan struct ipfw3_table_context *table_ctx; 1234408d548SBill Yuan struct radix_node_head *rnh; 1244408d548SBill Yuan 1254408d548SBill Yuan ioc_tbl = tbmsg->ioc_table; 1264408d548SBill Yuan table_ctx = ctx->table_ctx; 1274408d548SBill Yuan table_ctx += ioc_tbl->id; 1284408d548SBill Yuan table_ctx->count = 0; 1294408d548SBill Yuan 1304408d548SBill Yuan if (table_ctx->type == 1) { 1314408d548SBill Yuan rnh = table_ctx->node; 1324408d548SBill Yuan rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh); 1334408d548SBill Yuan } else if (table_ctx->type == 2) { 1344408d548SBill Yuan rnh = table_ctx->node; 1354408d548SBill Yuan rnh->rnh_walktree(rnh, flush_table_mac_entry, rnh); 1364408d548SBill Yuan } 1374408d548SBill Yuan table_ctx->type = 0; 1384408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 1394408d548SBill Yuan } 1404408d548SBill Yuan 1414408d548SBill Yuan static void 1424408d548SBill Yuan table_append_dispatch(netmsg_t nmsg) 1434408d548SBill Yuan { 1444408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 1454408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl; 1464408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 1474408d548SBill Yuan struct ipfw3_table_context *table_ctx; 1484408d548SBill Yuan struct radix_node_head *rnh; 1494408d548SBill Yuan 1504408d548SBill Yuan uint8_t mlen; 1514408d548SBill Yuan 1524408d548SBill Yuan ioc_tbl = tbmsg->ioc_table; 1534408d548SBill Yuan table_ctx = ctx->table_ctx; 1544408d548SBill Yuan table_ctx += ioc_tbl->id; 1554408d548SBill Yuan if (table_ctx->type != ioc_tbl->type) 1564408d548SBill Yuan goto done; 1574408d548SBill Yuan 1584408d548SBill Yuan if (table_ctx->type == 1 ) { 1594408d548SBill Yuan struct table_ip_entry *ent; 1604408d548SBill Yuan 1614408d548SBill Yuan rnh = table_ctx->node; 1624408d548SBill Yuan ent = kmalloc(sizeof(struct table_ip_entry), 1634408d548SBill Yuan M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 1644408d548SBill Yuan 1654408d548SBill Yuan if (ent == NULL) 1664408d548SBill Yuan return; 1674408d548SBill Yuan mlen = ioc_tbl->ip_ent->masklen; 1684408d548SBill Yuan ent->addr.sin_len = ent->mask.sin_len = 8; 1694408d548SBill Yuan ent->mask.sin_addr.s_addr = htonl(~((1 << (32 - mlen)) - 1)); 1704408d548SBill Yuan ent->addr.sin_addr.s_addr = ioc_tbl->ip_ent->addr & 1714408d548SBill Yuan ent->mask.sin_addr.s_addr; 1724408d548SBill Yuan 1734408d548SBill Yuan if (rnh->rnh_addaddr((char *)&ent->addr, 1744408d548SBill Yuan (char *)&ent->mask, rnh, 1754408d548SBill Yuan (void *)ent->rn) != NULL) { 1764408d548SBill Yuan table_ctx->count++; 1774408d548SBill Yuan } 1784408d548SBill Yuan } else if (table_ctx->type == 2 ) { 1794408d548SBill Yuan struct table_mac_entry *ent; 1804408d548SBill Yuan 1814408d548SBill Yuan rnh = table_ctx->node; 1824408d548SBill Yuan ent = kmalloc(sizeof(struct table_mac_entry), 1834408d548SBill Yuan M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 1844408d548SBill Yuan if (ent == NULL) 1854408d548SBill Yuan return; 1864408d548SBill Yuan ent->addr.sa_len = 8; 1874408d548SBill Yuan strncpy(ent->addr.sa_data, ioc_tbl->mac_ent->addr.octet, 6); 1884408d548SBill Yuan 1894408d548SBill Yuan if (rnh->rnh_addaddr((char *)&ent->addr, 1904408d548SBill Yuan NULL, rnh, (void *)ent->rn) != NULL) { 1914408d548SBill Yuan table_ctx->count++; 1924408d548SBill Yuan } 1934408d548SBill Yuan } 1944408d548SBill Yuan 1954408d548SBill Yuan done: 1964408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 1974408d548SBill Yuan } 1984408d548SBill Yuan 1994408d548SBill Yuan static void 2004408d548SBill Yuan table_remove_dispatch(netmsg_t nmsg) 2014408d548SBill Yuan { 2024408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 2034408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl; 2044408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 2054408d548SBill Yuan struct ipfw3_table_context *table_ctx; 2064408d548SBill Yuan struct radix_node_head *rnh; 2074408d548SBill Yuan struct table_entry *ent; 2084408d548SBill Yuan struct sockaddr_in sa, mask; 2094408d548SBill Yuan in_addr_t addr; 2104408d548SBill Yuan uint8_t mlen; 2114408d548SBill Yuan 2124408d548SBill Yuan ioc_tbl = tbmsg->ioc_table; 2134408d548SBill Yuan table_ctx = ctx->table_ctx; 2144408d548SBill Yuan table_ctx += ioc_tbl->id; 2154408d548SBill Yuan if (table_ctx->type != ioc_tbl->type) 2164408d548SBill Yuan goto done; 2174408d548SBill Yuan 2184408d548SBill Yuan rnh = table_ctx->node; 2194408d548SBill Yuan 2204408d548SBill Yuan mlen = ioc_tbl->ip_ent->masklen; 2214408d548SBill Yuan addr = ioc_tbl->ip_ent->addr; 2224408d548SBill Yuan 2234408d548SBill Yuan sa.sin_len = mask.sin_len = 8; 2244408d548SBill Yuan mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 2254408d548SBill Yuan sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 2264408d548SBill Yuan 2274408d548SBill Yuan ent = (struct table_entry *)rnh->rnh_deladdr((char *)&sa, (char *)&mask, rnh); 2284408d548SBill Yuan if (ent != NULL) { 2294408d548SBill Yuan table_ctx->count--; 2304408d548SBill Yuan kfree(ent, M_IPFW3_TABLE); 2314408d548SBill Yuan } 2324408d548SBill Yuan done: 2334408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 2344408d548SBill Yuan } 2354408d548SBill Yuan 2364408d548SBill Yuan int 2374408d548SBill Yuan flush_table_ip_entry(struct radix_node *rn, void *arg) 2384408d548SBill Yuan { 2394408d548SBill Yuan struct radix_node_head *rnh = arg; 2404408d548SBill Yuan struct table_ip_entry *ent; 2414408d548SBill Yuan 2424408d548SBill Yuan ent = (struct table_ip_entry *) 2434408d548SBill Yuan rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 2444408d548SBill Yuan if (ent != NULL) 2454408d548SBill Yuan kfree(ent, M_IPFW3_TABLE); 2464408d548SBill Yuan return (0); 2474408d548SBill Yuan } 2484408d548SBill Yuan 2494408d548SBill Yuan int 2504408d548SBill Yuan flush_table_mac_entry(struct radix_node *rn, void *arg) 2514408d548SBill Yuan { 2524408d548SBill Yuan struct radix_node_head *rnh = arg; 2534408d548SBill Yuan struct table_mac_entry *ent; 2544408d548SBill Yuan 2554408d548SBill Yuan ent = (struct table_mac_entry *) 2564408d548SBill Yuan rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 2574408d548SBill Yuan if (ent != NULL) 2584408d548SBill Yuan kfree(ent, M_IPFW3_TABLE); 2594408d548SBill Yuan return (0); 2604408d548SBill Yuan } 2614408d548SBill Yuan 2624408d548SBill Yuan static void 2634408d548SBill Yuan table_flush_dispatch(netmsg_t nmsg) 2644408d548SBill Yuan { 2654408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 2664408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl; 2674408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 2684408d548SBill Yuan struct ipfw3_table_context *table_ctx; 2694408d548SBill Yuan struct radix_node_head *rnh; 2704408d548SBill Yuan 2714408d548SBill Yuan ioc_tbl = tbmsg->ioc_table; 2724408d548SBill Yuan table_ctx = ctx->table_ctx; 2734408d548SBill Yuan table_ctx += ioc_tbl->id; 2744408d548SBill Yuan rnh = table_ctx->node; 2754408d548SBill Yuan table_ctx->count = 0; 2764408d548SBill Yuan 2774408d548SBill Yuan rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh); 2784408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 2794408d548SBill Yuan } 2804408d548SBill Yuan 2814408d548SBill Yuan /* 2824408d548SBill Yuan * rename the table 2834408d548SBill Yuan */ 2844408d548SBill Yuan static void 2854408d548SBill Yuan table_rename_dispatch(netmsg_t nmsg) 2864408d548SBill Yuan { 2874408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 2884408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl; 2894408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 2904408d548SBill Yuan struct ipfw3_table_context *table_ctx; 2914408d548SBill Yuan 2924408d548SBill Yuan ioc_tbl = tbmsg->ioc_table; 2934408d548SBill Yuan table_ctx = ctx->table_ctx; 2944408d548SBill Yuan table_ctx += ioc_tbl->id; 2954408d548SBill Yuan strlcpy(table_ctx->name, ioc_tbl->name, IPFW_TABLE_NAME_LEN); 2964408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 2974408d548SBill Yuan } 2984408d548SBill Yuan 2994408d548SBill Yuan /* 3004408d548SBill Yuan * list all the overview information about each table 3014408d548SBill Yuan */ 3024408d548SBill Yuan int 3034408d548SBill Yuan ip_fw3_ctl_table_list(struct sockopt *sopt) 3044408d548SBill Yuan { 3054408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 3064408d548SBill Yuan struct ipfw3_table_context *table_ctx = ctx->table_ctx; 3074408d548SBill Yuan struct ipfw_ioc_table *ioc_table; 3084408d548SBill Yuan int i, error = 0, size; 3094408d548SBill Yuan 3104408d548SBill Yuan size = IPFW_TABLES_MAX * sizeof(struct ipfw_ioc_table); 3114408d548SBill Yuan if (sopt->sopt_valsize < size) { 3124408d548SBill Yuan /* sopt_val is not big enough */ 3134408d548SBill Yuan bzero(sopt->sopt_val, sopt->sopt_valsize); 3144408d548SBill Yuan return 0; 3154408d548SBill Yuan } 3164408d548SBill Yuan ioc_table = (struct ipfw_ioc_table *)sopt->sopt_val; 3174408d548SBill Yuan for (i = 0; i < IPFW_TABLES_MAX; i++, ioc_table++, table_ctx++) { 3184408d548SBill Yuan ioc_table->id = i; 3194408d548SBill Yuan ioc_table->type = table_ctx->type; 3204408d548SBill Yuan ioc_table->count = table_ctx->count; 3214408d548SBill Yuan strlcpy(ioc_table->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 3224408d548SBill Yuan } 3234408d548SBill Yuan sopt->sopt_valsize = size; 3244408d548SBill Yuan return error; 3254408d548SBill Yuan } 3264408d548SBill Yuan 3274408d548SBill Yuan /* 3284408d548SBill Yuan * remove an item from the table 3294408d548SBill Yuan */ 3304408d548SBill Yuan int 3314408d548SBill Yuan ip_fw3_ctl_table_remove(struct sockopt *sopt) 3324408d548SBill Yuan { 3334408d548SBill Yuan struct netmsg_table tbmsg; 3344408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg)); 3354408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val; 3364408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 3374408d548SBill Yuan 0, table_remove_dispatch); 3384408d548SBill Yuan netisr_domsg(&tbmsg.base, 0); 3394408d548SBill Yuan return tbmsg.retval; 3404408d548SBill Yuan } 3414408d548SBill Yuan 3424408d548SBill Yuan /* 3434408d548SBill Yuan * flush everything inside the table 3444408d548SBill Yuan */ 3454408d548SBill Yuan int 3464408d548SBill Yuan ip_fw3_ctl_table_flush(struct sockopt *sopt) 3474408d548SBill Yuan { 3484408d548SBill Yuan struct netmsg_table tbmsg; 3494408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg)); 3504408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val; 3514408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 3524408d548SBill Yuan 0, table_flush_dispatch); 3534408d548SBill Yuan netisr_domsg(&tbmsg.base, 0); 3544408d548SBill Yuan return tbmsg.retval; 3554408d548SBill Yuan } 3564408d548SBill Yuan 3574408d548SBill Yuan /* 3584408d548SBill Yuan * dump the entries into the ioc_table 3594408d548SBill Yuan */ 3604408d548SBill Yuan int 3614408d548SBill Yuan dump_table_ip_entry(struct radix_node *rn, void *arg) 3624408d548SBill Yuan { 3634408d548SBill Yuan struct table_ip_entry *ent = (struct table_ip_entry *)rn; 3644408d548SBill Yuan struct ipfw_ioc_table_ip_entry *ioc_ent; 3654408d548SBill Yuan struct ipfw_ioc_table *tbl = arg; 3664408d548SBill Yuan struct sockaddr_in *addr, *mask; 3674408d548SBill Yuan 3684408d548SBill Yuan addr = &ent->addr; 3694408d548SBill Yuan mask = &ent->mask; 3704408d548SBill Yuan 3714408d548SBill Yuan ioc_ent = &tbl->ip_ent[tbl->count]; 3724408d548SBill Yuan if (in_nullhost(mask->sin_addr)) 3734408d548SBill Yuan ioc_ent->masklen = 0; 3744408d548SBill Yuan else 3754408d548SBill Yuan ioc_ent->masklen = 33 - ffs(ntohl(mask->sin_addr.s_addr)); 3764408d548SBill Yuan ioc_ent->addr = addr->sin_addr.s_addr; 3774408d548SBill Yuan tbl->count++; 3784408d548SBill Yuan return (0); 3794408d548SBill Yuan } 3804408d548SBill Yuan 3814408d548SBill Yuan int 3824408d548SBill Yuan dump_table_mac_entry(struct radix_node *rn, void *arg) 3834408d548SBill Yuan { 3844408d548SBill Yuan struct table_mac_entry *ent = (struct table_mac_entry *)rn; 3854408d548SBill Yuan struct ipfw_ioc_table_mac_entry *ioc_ent; 3864408d548SBill Yuan struct ipfw_ioc_table *tbl = arg; 3874408d548SBill Yuan ioc_ent = &tbl->mac_ent[tbl->count]; 3884408d548SBill Yuan strncpy(ioc_ent->addr.octet, ent->addr.sa_data, 6); 3894408d548SBill Yuan tbl->count++; 3904408d548SBill Yuan return (0); 3914408d548SBill Yuan } 3924408d548SBill Yuan 3934408d548SBill Yuan /* 3944408d548SBill Yuan * get and display all items in the table 3954408d548SBill Yuan */ 3964408d548SBill Yuan int 3974408d548SBill Yuan ip_fw3_ctl_table_show(struct sockopt *sopt) 3984408d548SBill Yuan { 3994408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 4004408d548SBill Yuan struct ipfw3_table_context *table_ctx; 4014408d548SBill Yuan struct radix_node_head *rnh; 4024408d548SBill Yuan struct ipfw_ioc_table *tbl; 4034408d548SBill Yuan void *data; 4044408d548SBill Yuan int size; 4054408d548SBill Yuan 4064408d548SBill Yuan int *id = (int *)sopt->sopt_val; 4074408d548SBill Yuan table_ctx = ctx->table_ctx; 4084408d548SBill Yuan table_ctx += *id; 4094408d548SBill Yuan if (table_ctx->type == 1) { 4104408d548SBill Yuan size = table_ctx->count * sizeof(struct ipfw_ioc_table_ip_entry) + 4114408d548SBill Yuan sizeof(struct ipfw_ioc_table); 4124408d548SBill Yuan if (sopt->sopt_valsize < size) { 4134408d548SBill Yuan /* sopt_val is not big enough */ 4144408d548SBill Yuan bzero(sopt->sopt_val, sopt->sopt_valsize); 4154408d548SBill Yuan return 0; 4164408d548SBill Yuan } 4174408d548SBill Yuan data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 4184408d548SBill Yuan tbl = (struct ipfw_ioc_table *)data; 4194408d548SBill Yuan tbl->id = *id; 4204408d548SBill Yuan tbl->type = table_ctx->type; 4214408d548SBill Yuan strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 4224408d548SBill Yuan rnh = table_ctx->node; 4234408d548SBill Yuan rnh->rnh_walktree(rnh, dump_table_ip_entry, tbl); 4244408d548SBill Yuan bcopy(tbl, sopt->sopt_val, size); 4254408d548SBill Yuan sopt->sopt_valsize = size; 4264408d548SBill Yuan kfree(data, M_IPFW3_TABLE); 4274408d548SBill Yuan } else if (table_ctx->type == 2) { 4284408d548SBill Yuan size = table_ctx->count * sizeof(struct ipfw_ioc_table_mac_entry) + 4294408d548SBill Yuan sizeof(struct ipfw_ioc_table); 4304408d548SBill Yuan if (sopt->sopt_valsize < size) { 4314408d548SBill Yuan /* sopt_val is not big enough */ 4324408d548SBill Yuan bzero(sopt->sopt_val, sopt->sopt_valsize); 4334408d548SBill Yuan return 0; 4344408d548SBill Yuan } 4354408d548SBill Yuan data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 4364408d548SBill Yuan tbl = (struct ipfw_ioc_table *)data; 4374408d548SBill Yuan tbl->id = *id; 4384408d548SBill Yuan tbl->type = table_ctx->type; 4394408d548SBill Yuan strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 4404408d548SBill Yuan rnh = table_ctx->node; 4414408d548SBill Yuan rnh->rnh_walktree(rnh, dump_table_mac_entry, tbl); 4424408d548SBill Yuan bcopy(tbl, sopt->sopt_val, size); 4434408d548SBill Yuan sopt->sopt_valsize = size; 4444408d548SBill Yuan kfree(data, M_IPFW3_TABLE); 4454408d548SBill Yuan } 4464408d548SBill Yuan return 0; 4474408d548SBill Yuan } 4484408d548SBill Yuan 4494408d548SBill Yuan /* 4504408d548SBill Yuan * test whether the ip is in the table 4514408d548SBill Yuan */ 4524408d548SBill Yuan int 4534408d548SBill Yuan ip_fw3_ctl_table_test(struct sockopt *sopt) 4544408d548SBill Yuan { 4554408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 4564408d548SBill Yuan struct ipfw3_table_context *table_ctx; 4574408d548SBill Yuan struct radix_node_head *rnh; 4584408d548SBill Yuan struct ipfw_ioc_table *tbl; 4594408d548SBill Yuan 4604408d548SBill Yuan tbl = (struct ipfw_ioc_table *)sopt->sopt_val; 4614408d548SBill Yuan table_ctx = ctx->table_ctx; 4624408d548SBill Yuan table_ctx += tbl->id; 4634408d548SBill Yuan 4644408d548SBill Yuan if (table_ctx->type != tbl->type) 4654408d548SBill Yuan goto done; 4664408d548SBill Yuan 4674408d548SBill Yuan rnh = table_ctx->node; 4684408d548SBill Yuan if (tbl->type == 1) { 4694408d548SBill Yuan struct sockaddr_in sa; 4704408d548SBill Yuan sa.sin_len = 8; 4714408d548SBill Yuan sa.sin_addr.s_addr = tbl->ip_ent->addr; 4724408d548SBill Yuan 4734408d548SBill Yuan if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL) 4744408d548SBill Yuan return 0; 4754408d548SBill Yuan } else if (tbl->type == 2) { 4764408d548SBill Yuan struct sockaddr sa; 4774408d548SBill Yuan sa.sa_len = 8; 4784408d548SBill Yuan strncpy(sa.sa_data, tbl->mac_ent->addr.octet, 6); 4794408d548SBill Yuan 4804408d548SBill Yuan if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL) 4814408d548SBill Yuan return 0; 4824408d548SBill Yuan } else { 4834408d548SBill Yuan /* XXX TODO */ 4844408d548SBill Yuan } 4854408d548SBill Yuan done: 4864408d548SBill Yuan return 1; 4874408d548SBill Yuan } 4884408d548SBill Yuan 4894408d548SBill Yuan /* 4904408d548SBill Yuan * activate the table 4914408d548SBill Yuan */ 4924408d548SBill Yuan int 4934408d548SBill Yuan ip_fw3_ctl_table_create(struct sockopt *sopt) 4944408d548SBill Yuan { 4954408d548SBill Yuan struct netmsg_table tbmsg; 4964408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg)); 4974408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val; 4984408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 4994408d548SBill Yuan 0, table_create_dispatch); 5004408d548SBill Yuan netisr_domsg(&tbmsg.base, 0); 5014408d548SBill Yuan return tbmsg.retval; 5024408d548SBill Yuan } 5034408d548SBill Yuan 5044408d548SBill Yuan /* 5054408d548SBill Yuan * deactivate the table 5064408d548SBill Yuan */ 5074408d548SBill Yuan int 5084408d548SBill Yuan ip_fw3_ctl_table_delete(struct sockopt *sopt) 5094408d548SBill Yuan { 5104408d548SBill Yuan struct netmsg_table tbmsg; 5114408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg)); 5124408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val; 5134408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 5144408d548SBill Yuan 0, table_delete_dispatch); 5154408d548SBill Yuan netisr_domsg(&tbmsg.base, 0); 5164408d548SBill Yuan return tbmsg.retval; 5174408d548SBill Yuan } 5184408d548SBill Yuan 5194408d548SBill Yuan /* 5204408d548SBill Yuan * append an item into the table 5214408d548SBill Yuan */ 5224408d548SBill Yuan int 5234408d548SBill Yuan ip_fw3_ctl_table_append(struct sockopt *sopt) 5244408d548SBill Yuan { 5254408d548SBill Yuan struct netmsg_table tbmsg; 5264408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg)); 5274408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val; 5284408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 5294408d548SBill Yuan 0, table_append_dispatch); 5304408d548SBill Yuan netisr_domsg(&tbmsg.base, 0); 5314408d548SBill Yuan return tbmsg.retval; 5324408d548SBill Yuan } 5334408d548SBill Yuan 5344408d548SBill Yuan /* 5354408d548SBill Yuan * rename an table 5364408d548SBill Yuan */ 5374408d548SBill Yuan int 5384408d548SBill Yuan ip_fw3_ctl_table_rename(struct sockopt *sopt) 5394408d548SBill Yuan { 5404408d548SBill Yuan struct netmsg_table tbmsg; 5414408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg)); 5424408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val; 5434408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 5444408d548SBill Yuan 0, table_rename_dispatch); 5454408d548SBill Yuan netisr_domsg(&tbmsg.base, 0); 5464408d548SBill Yuan return tbmsg.retval; 5474408d548SBill Yuan } 5484408d548SBill Yuan 5494408d548SBill Yuan /* 5504408d548SBill Yuan * sockopt handler 5514408d548SBill Yuan */ 5524408d548SBill Yuan int 5534408d548SBill Yuan ip_fw3_ctl_table_sockopt(struct sockopt *sopt) 5544408d548SBill Yuan { 5554408d548SBill Yuan int error = 0; 5564408d548SBill Yuan switch (sopt->sopt_name) { 5574408d548SBill Yuan case IP_FW_TABLE_CREATE: 5584408d548SBill Yuan error = ip_fw3_ctl_table_create(sopt); 5594408d548SBill Yuan break; 5604408d548SBill Yuan case IP_FW_TABLE_DELETE: 5614408d548SBill Yuan error = ip_fw3_ctl_table_delete(sopt); 5624408d548SBill Yuan break; 5634408d548SBill Yuan case IP_FW_TABLE_APPEND: 5644408d548SBill Yuan error = ip_fw3_ctl_table_append(sopt); 5654408d548SBill Yuan break; 5664408d548SBill Yuan case IP_FW_TABLE_REMOVE: 5674408d548SBill Yuan error = ip_fw3_ctl_table_remove(sopt); 5684408d548SBill Yuan break; 5694408d548SBill Yuan case IP_FW_TABLE_LIST: 5704408d548SBill Yuan error = ip_fw3_ctl_table_list(sopt); 5714408d548SBill Yuan break; 5724408d548SBill Yuan case IP_FW_TABLE_FLUSH: 5734408d548SBill Yuan error = ip_fw3_ctl_table_flush(sopt); 5744408d548SBill Yuan break; 5754408d548SBill Yuan case IP_FW_TABLE_SHOW: 5764408d548SBill Yuan error = ip_fw3_ctl_table_show(sopt); 5774408d548SBill Yuan break; 5784408d548SBill Yuan case IP_FW_TABLE_TEST: 5794408d548SBill Yuan error = ip_fw3_ctl_table_test(sopt); 5804408d548SBill Yuan break; 5814408d548SBill Yuan case IP_FW_TABLE_RENAME: 5824408d548SBill Yuan error = ip_fw3_ctl_table_rename(sopt); 5834408d548SBill Yuan break; 5844408d548SBill Yuan default: 5854408d548SBill Yuan kprintf("ipfw table invalid socket option %d\n", 5864408d548SBill Yuan sopt->sopt_name); 5874408d548SBill Yuan } 5884408d548SBill Yuan return error; 5894408d548SBill Yuan } 5904408d548SBill Yuan 5914408d548SBill Yuan static void 5924408d548SBill Yuan table_init_ctx_dispatch(netmsg_t nmsg) 5934408d548SBill Yuan { 5944408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 5954408d548SBill Yuan ctx->table_ctx = kmalloc(sizeof(struct ipfw3_table_context) * IPFW_TABLES_MAX, 5964408d548SBill Yuan M_IPFW3_TABLE, M_WAITOK | M_ZERO); 5974408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 5984408d548SBill Yuan } 5994408d548SBill Yuan 6004408d548SBill Yuan /* 6014408d548SBill Yuan * release the memory of the tables 6024408d548SBill Yuan */ 6034408d548SBill Yuan void 6044408d548SBill Yuan table_fini(void) 6054408d548SBill Yuan { 6064408d548SBill Yuan struct ipfw3_table_context *table_ctx, *tmp_table; 6074408d548SBill Yuan struct radix_node_head *rnh; 6084408d548SBill Yuan int cpu, id; 6094408d548SBill Yuan for (cpu = 0; cpu < ncpus; cpu++) { 6104408d548SBill Yuan table_ctx = fw3_ctx[cpu]->table_ctx; 6114408d548SBill Yuan tmp_table = table_ctx; 6124408d548SBill Yuan for (id = 0; id < IPFW_TABLES_MAX; id++, table_ctx++) { 6134408d548SBill Yuan if (table_ctx->type == 1) { 6144408d548SBill Yuan rnh = table_ctx->node; 6154408d548SBill Yuan rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh); 6164408d548SBill Yuan } else if (table_ctx->type == 2) { 6174408d548SBill Yuan rnh = table_ctx->node; 6184408d548SBill Yuan rnh->rnh_walktree(rnh, flush_table_mac_entry, rnh); 6194408d548SBill Yuan } 6204408d548SBill Yuan } 6214408d548SBill Yuan kfree(tmp_table, M_IPFW3_TABLE); 6224408d548SBill Yuan } 6234408d548SBill Yuan } 6244408d548SBill Yuan 6254408d548SBill Yuan /* 6264408d548SBill Yuan * it will be invoked during init of ipfw3 6274408d548SBill Yuan * this function will prepare the tables 6284408d548SBill Yuan */ 6294408d548SBill Yuan void 6304408d548SBill Yuan table_init_dispatch(netmsg_t nmsg) 6314408d548SBill Yuan { 6324408d548SBill Yuan int error = 0; 6334408d548SBill Yuan struct netmsg_base nmsg_base; 6344408d548SBill Yuan bzero(&nmsg_base, sizeof(nmsg_base)); 6354408d548SBill Yuan netmsg_init(&nmsg_base, NULL, &curthread->td_msgport, 6364408d548SBill Yuan 0, table_init_ctx_dispatch); 6374408d548SBill Yuan netisr_domsg(&nmsg_base, 0); 6384408d548SBill Yuan lwkt_replymsg(&nmsg->lmsg, error); 6394408d548SBill Yuan } 640