xref: /dflybsd-src/sys/net/ipfw3_basic/ip_fw3_table.c (revision bff82488b6f45c2f067e4c552e649b1d3e07cd7c)
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