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
51bff82488SAaron LI #include <net/if.h>
52bff82488SAaron LI #include <net/route.h>
53bff82488SAaron LI #include <net/pfil.h>
54bff82488SAaron LI #include <net/netmsg2.h>
55bff82488SAaron LI #include <net/ethernet.h>
56bff82488SAaron LI
574408d548SBill Yuan #include <netinet/in.h>
584408d548SBill Yuan #include <netinet/in_systm.h>
594408d548SBill Yuan #include <netinet/in_var.h>
604408d548SBill Yuan #include <netinet/in_pcb.h>
614408d548SBill Yuan #include <netinet/ip.h>
624408d548SBill Yuan #include <netinet/ip_var.h>
634408d548SBill Yuan #include <netinet/ip_icmp.h>
644408d548SBill Yuan #include <netinet/tcp.h>
654408d548SBill Yuan #include <netinet/tcp_timer.h>
664408d548SBill Yuan #include <netinet/tcp_var.h>
674408d548SBill Yuan #include <netinet/tcpip.h>
684408d548SBill Yuan #include <netinet/udp.h>
694408d548SBill Yuan #include <netinet/udp_var.h>
704408d548SBill Yuan #include <netinet/ip_divert.h>
714408d548SBill Yuan #include <netinet/if_ether.h>
724408d548SBill Yuan
734408d548SBill Yuan #include <net/ipfw3/ip_fw.h>
744408d548SBill Yuan #include <net/ipfw3_basic/ip_fw3_table.h>
754408d548SBill Yuan
764408d548SBill Yuan MALLOC_DEFINE(M_IPFW3_TABLE, "IPFW3_TABLE", "mem for ip_fw3 table");
774408d548SBill Yuan
784408d548SBill Yuan extern struct ipfw3_context *fw3_ctx[MAXCPU];
79de23f38fSBill Yuan extern ip_fw_ctl_t *ip_fw3_ctl_table_ptr;
804408d548SBill Yuan
814408d548SBill Yuan /*
824408d548SBill Yuan * activate/create the table by setup the type and reset counts.
834408d548SBill Yuan */
849d11a266SBill Yuan void
table_create_dispatch(netmsg_t nmsg)854408d548SBill Yuan table_create_dispatch(netmsg_t nmsg)
864408d548SBill Yuan {
874408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
884408d548SBill Yuan struct ipfw_ioc_table *ioc_table;
894408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
904408d548SBill Yuan struct ipfw3_table_context *table_ctx;
914408d548SBill Yuan ioc_table = tbmsg->ioc_table;
924408d548SBill Yuan int id = ioc_table->id;
934408d548SBill Yuan
944408d548SBill Yuan table_ctx = ctx->table_ctx;
954408d548SBill Yuan table_ctx += id;
964408d548SBill Yuan table_ctx->type = ioc_table->type;
974408d548SBill Yuan table_ctx->count = 0;
984408d548SBill Yuan strlcpy(table_ctx->name , ioc_table->name, IPFW_TABLE_NAME_LEN);
994408d548SBill Yuan if (table_ctx->type == 1) {
1006823c302SAaron LI rn_inithead(&table_ctx->mask, NULL, 0);
1016823c302SAaron LI rn_inithead(&table_ctx->node, table_ctx->mask,
102a4f40cc8SAaron LI offsetof(struct sockaddr_in, sin_addr));
1034408d548SBill Yuan } else if (table_ctx->type == 2) {
1046823c302SAaron LI rn_inithead(&table_ctx->mask, NULL, 0);
1056823c302SAaron LI rn_inithead(&table_ctx->node, table_ctx->mask,
106a4f40cc8SAaron LI offsetof(struct sockaddr, sa_data));
1074408d548SBill Yuan } else {
1084408d548SBill Yuan goto done;
1094408d548SBill Yuan }
1104408d548SBill Yuan done:
1114408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
1124408d548SBill Yuan }
1134408d548SBill Yuan
1144408d548SBill Yuan /*
1154408d548SBill Yuan * clean the table, especially the node
1164408d548SBill Yuan */
1179d11a266SBill Yuan void
table_delete_dispatch(netmsg_t nmsg)1184408d548SBill Yuan table_delete_dispatch(netmsg_t nmsg)
1194408d548SBill Yuan {
1204408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
1214408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl;
1224408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
1234408d548SBill Yuan struct ipfw3_table_context *table_ctx;
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
1300d7b85c8SAaron LI rn_flush(table_ctx->node, flush_table_entry);
1310d7b85c8SAaron LI /* XXX: should free the tree: rn_freehead(table_ctx->node) */
1324408d548SBill Yuan table_ctx->type = 0;
1334408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
1344408d548SBill Yuan }
1354408d548SBill Yuan
1369d11a266SBill Yuan void
table_append_dispatch(netmsg_t nmsg)1374408d548SBill Yuan table_append_dispatch(netmsg_t nmsg)
1384408d548SBill Yuan {
1394408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
1404408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl;
1414408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
1424408d548SBill Yuan struct ipfw3_table_context *table_ctx;
1434408d548SBill Yuan struct radix_node_head *rnh;
1444408d548SBill Yuan
1454408d548SBill Yuan uint8_t mlen;
1464408d548SBill Yuan
1474408d548SBill Yuan ioc_tbl = tbmsg->ioc_table;
1484408d548SBill Yuan table_ctx = ctx->table_ctx;
1494408d548SBill Yuan table_ctx += ioc_tbl->id;
1504408d548SBill Yuan if (table_ctx->type != ioc_tbl->type)
1514408d548SBill Yuan goto done;
1524408d548SBill Yuan
1534408d548SBill Yuan if (table_ctx->type == 1) {
1544408d548SBill Yuan struct table_ip_entry *ent;
1554408d548SBill Yuan
1564408d548SBill Yuan rnh = table_ctx->node;
1574408d548SBill Yuan ent = kmalloc(sizeof(struct table_ip_entry),
1584408d548SBill Yuan M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
1594408d548SBill Yuan if (ent == NULL)
1604408d548SBill Yuan return;
1614408d548SBill Yuan mlen = ioc_tbl->ip_ent->masklen;
162751adc91SAaron LI ent->addr.sin_len = sizeof(ent->addr);
163751adc91SAaron LI ent->mask.sin_len = sizeof(ent->mask);
1644408d548SBill Yuan ent->mask.sin_addr.s_addr = htonl(~((1 << (32 - mlen)) - 1));
1654408d548SBill Yuan ent->addr.sin_addr.s_addr = ioc_tbl->ip_ent->addr &
1664408d548SBill Yuan ent->mask.sin_addr.s_addr;
1674408d548SBill Yuan
168*d8449084SAaron LI if (rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, ent->rn)
169*d8449084SAaron LI != NULL)
1704408d548SBill Yuan table_ctx->count++;
1714408d548SBill Yuan } else if (table_ctx->type == 2) {
1724408d548SBill Yuan struct table_mac_entry *ent;
1734408d548SBill Yuan
1744408d548SBill Yuan rnh = table_ctx->node;
1754408d548SBill Yuan ent = kmalloc(sizeof(struct table_mac_entry),
1764408d548SBill Yuan M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
1774408d548SBill Yuan if (ent == NULL)
1784408d548SBill Yuan return;
179751adc91SAaron LI ent->addr.sa_len = offsetof(struct sockaddr, sa_data[6]);
1804408d548SBill Yuan strncpy(ent->addr.sa_data, ioc_tbl->mac_ent->addr.octet, 6);
1814408d548SBill Yuan
182*d8449084SAaron LI if (rnh->rnh_addaddr(&ent->addr, NULL, rnh, ent->rn) != NULL)
1834408d548SBill Yuan table_ctx->count++;
1844408d548SBill Yuan }
1854408d548SBill Yuan
1864408d548SBill Yuan done:
1874408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
1884408d548SBill Yuan }
1894408d548SBill Yuan
1909d11a266SBill Yuan void
table_remove_dispatch(netmsg_t nmsg)1914408d548SBill Yuan table_remove_dispatch(netmsg_t nmsg)
1924408d548SBill Yuan {
1934408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
1944408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl;
1954408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
1964408d548SBill Yuan struct ipfw3_table_context *table_ctx;
1974408d548SBill Yuan struct radix_node_head *rnh;
1984408d548SBill Yuan struct table_entry *ent;
1994408d548SBill Yuan struct sockaddr_in sa, mask;
2004408d548SBill Yuan in_addr_t addr;
2014408d548SBill Yuan uint8_t mlen;
2024408d548SBill Yuan
2034408d548SBill Yuan ioc_tbl = tbmsg->ioc_table;
2044408d548SBill Yuan table_ctx = ctx->table_ctx;
2054408d548SBill Yuan table_ctx += ioc_tbl->id;
2064408d548SBill Yuan if (table_ctx->type != ioc_tbl->type)
2074408d548SBill Yuan goto done;
2084408d548SBill Yuan
2094408d548SBill Yuan rnh = table_ctx->node;
2104408d548SBill Yuan
2114408d548SBill Yuan mlen = ioc_tbl->ip_ent->masklen;
2124408d548SBill Yuan addr = ioc_tbl->ip_ent->addr;
2134408d548SBill Yuan
2144408d548SBill Yuan sa.sin_len = mask.sin_len = 8;
2154408d548SBill Yuan mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
2164408d548SBill Yuan sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
2174408d548SBill Yuan
218*d8449084SAaron LI ent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh);
2194408d548SBill Yuan if (ent != NULL) {
2204408d548SBill Yuan table_ctx->count--;
2214408d548SBill Yuan kfree(ent, M_IPFW3_TABLE);
2224408d548SBill Yuan }
2234408d548SBill Yuan done:
2244408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
2254408d548SBill Yuan }
2264408d548SBill Yuan
2270d7b85c8SAaron LI void
flush_table_entry(struct radix_node * rn)2280d7b85c8SAaron LI flush_table_entry(struct radix_node *rn)
2294408d548SBill Yuan {
2300d7b85c8SAaron LI kfree(rn, M_IPFW3_TABLE);
2314408d548SBill Yuan }
2324408d548SBill Yuan
2339d11a266SBill Yuan void
table_flush_dispatch(netmsg_t nmsg)2344408d548SBill Yuan table_flush_dispatch(netmsg_t nmsg)
2354408d548SBill Yuan {
2364408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
2374408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl;
2384408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
2394408d548SBill Yuan struct ipfw3_table_context *table_ctx;
2404408d548SBill Yuan struct radix_node_head *rnh;
2414408d548SBill Yuan
2424408d548SBill Yuan ioc_tbl = tbmsg->ioc_table;
2434408d548SBill Yuan table_ctx = ctx->table_ctx;
2444408d548SBill Yuan table_ctx += ioc_tbl->id;
2454408d548SBill Yuan rnh = table_ctx->node;
2464408d548SBill Yuan table_ctx->count = 0;
2474408d548SBill Yuan
2480d7b85c8SAaron LI rn_flush(rnh, flush_table_entry);
2494408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
2504408d548SBill Yuan }
2514408d548SBill Yuan
2524408d548SBill Yuan /*
2534408d548SBill Yuan * rename the table
2544408d548SBill Yuan */
2559d11a266SBill Yuan void
table_rename_dispatch(netmsg_t nmsg)2564408d548SBill Yuan table_rename_dispatch(netmsg_t nmsg)
2574408d548SBill Yuan {
2584408d548SBill Yuan struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
2594408d548SBill Yuan struct ipfw_ioc_table *ioc_tbl;
2604408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
2614408d548SBill Yuan struct ipfw3_table_context *table_ctx;
2624408d548SBill Yuan
2634408d548SBill Yuan ioc_tbl = tbmsg->ioc_table;
2644408d548SBill Yuan table_ctx = ctx->table_ctx;
2654408d548SBill Yuan table_ctx += ioc_tbl->id;
2664408d548SBill Yuan strlcpy(table_ctx->name, ioc_tbl->name, IPFW_TABLE_NAME_LEN);
2674408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
2684408d548SBill Yuan }
2694408d548SBill Yuan
2704408d548SBill Yuan /*
2714408d548SBill Yuan * list all the overview information about each table
2724408d548SBill Yuan */
2734408d548SBill Yuan int
ip_fw3_ctl_table_list(struct sockopt * sopt)2744408d548SBill Yuan ip_fw3_ctl_table_list(struct sockopt *sopt)
2754408d548SBill Yuan {
2764408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
2774408d548SBill Yuan struct ipfw3_table_context *table_ctx = ctx->table_ctx;
2784408d548SBill Yuan struct ipfw_ioc_table *ioc_table;
2794408d548SBill Yuan int i, error = 0, size;
2804408d548SBill Yuan
2814408d548SBill Yuan size = IPFW_TABLES_MAX * sizeof(struct ipfw_ioc_table);
2824408d548SBill Yuan if (sopt->sopt_valsize < size) {
2834408d548SBill Yuan /* sopt_val is not big enough */
2844408d548SBill Yuan bzero(sopt->sopt_val, sopt->sopt_valsize);
2854408d548SBill Yuan return 0;
2864408d548SBill Yuan }
2874408d548SBill Yuan ioc_table = (struct ipfw_ioc_table *)sopt->sopt_val;
2884408d548SBill Yuan for (i = 0; i < IPFW_TABLES_MAX; i++, ioc_table++, table_ctx++) {
2894408d548SBill Yuan ioc_table->id = i;
2904408d548SBill Yuan ioc_table->type = table_ctx->type;
2914408d548SBill Yuan ioc_table->count = table_ctx->count;
2924408d548SBill Yuan strlcpy(ioc_table->name, table_ctx->name, IPFW_TABLE_NAME_LEN);
2934408d548SBill Yuan }
2944408d548SBill Yuan sopt->sopt_valsize = size;
2954408d548SBill Yuan return error;
2964408d548SBill Yuan }
2974408d548SBill Yuan
2984408d548SBill Yuan /*
2994408d548SBill Yuan * remove an item from the table
3004408d548SBill Yuan */
3014408d548SBill Yuan int
ip_fw3_ctl_table_remove(struct sockopt * sopt)3024408d548SBill Yuan ip_fw3_ctl_table_remove(struct sockopt *sopt)
3034408d548SBill Yuan {
3044408d548SBill Yuan struct netmsg_table tbmsg;
3054408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg));
3064408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val;
3074408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
3084408d548SBill Yuan 0, table_remove_dispatch);
3094408d548SBill Yuan netisr_domsg(&tbmsg.base, 0);
3104408d548SBill Yuan return tbmsg.retval;
3114408d548SBill Yuan }
3124408d548SBill Yuan
3134408d548SBill Yuan /*
3144408d548SBill Yuan * flush everything inside the table
3154408d548SBill Yuan */
3164408d548SBill Yuan int
ip_fw3_ctl_table_flush(struct sockopt * sopt)3174408d548SBill Yuan ip_fw3_ctl_table_flush(struct sockopt *sopt)
3184408d548SBill Yuan {
3194408d548SBill Yuan struct netmsg_table tbmsg;
3204408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg));
3214408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val;
3224408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
3234408d548SBill Yuan 0, table_flush_dispatch);
3244408d548SBill Yuan netisr_domsg(&tbmsg.base, 0);
3254408d548SBill Yuan return tbmsg.retval;
3264408d548SBill Yuan }
3274408d548SBill Yuan
3284408d548SBill Yuan /*
3294408d548SBill Yuan * dump the entries into the ioc_table
3304408d548SBill Yuan */
3314408d548SBill Yuan int
dump_table_ip_entry(struct radix_node * rn,void * arg)3324408d548SBill Yuan dump_table_ip_entry(struct radix_node *rn, void *arg)
3334408d548SBill Yuan {
3344408d548SBill Yuan struct table_ip_entry *ent = (struct table_ip_entry *)rn;
3354408d548SBill Yuan struct ipfw_ioc_table_ip_entry *ioc_ent;
3364408d548SBill Yuan struct ipfw_ioc_table *tbl = arg;
3374408d548SBill Yuan struct sockaddr_in *addr, *mask;
3384408d548SBill Yuan
3394408d548SBill Yuan addr = &ent->addr;
3404408d548SBill Yuan mask = &ent->mask;
3414408d548SBill Yuan
3424408d548SBill Yuan ioc_ent = &tbl->ip_ent[tbl->count];
3434408d548SBill Yuan if (in_nullhost(mask->sin_addr))
3444408d548SBill Yuan ioc_ent->masklen = 0;
3454408d548SBill Yuan else
3464408d548SBill Yuan ioc_ent->masklen = 33 - ffs(ntohl(mask->sin_addr.s_addr));
3474408d548SBill Yuan ioc_ent->addr = addr->sin_addr.s_addr;
3484408d548SBill Yuan tbl->count++;
3494408d548SBill Yuan return (0);
3504408d548SBill Yuan }
3514408d548SBill Yuan
3524408d548SBill Yuan int
dump_table_mac_entry(struct radix_node * rn,void * arg)3534408d548SBill Yuan dump_table_mac_entry(struct radix_node *rn, void *arg)
3544408d548SBill Yuan {
3554408d548SBill Yuan struct table_mac_entry *ent = (struct table_mac_entry *)rn;
3564408d548SBill Yuan struct ipfw_ioc_table_mac_entry *ioc_ent;
3574408d548SBill Yuan struct ipfw_ioc_table *tbl = arg;
3584408d548SBill Yuan ioc_ent = &tbl->mac_ent[tbl->count];
3594408d548SBill Yuan strncpy(ioc_ent->addr.octet, ent->addr.sa_data, 6);
3604408d548SBill Yuan tbl->count++;
3614408d548SBill Yuan return (0);
3624408d548SBill Yuan }
3634408d548SBill Yuan
3644408d548SBill Yuan /*
3654408d548SBill Yuan * get and display all items in the table
3664408d548SBill Yuan */
3674408d548SBill Yuan int
ip_fw3_ctl_table_show(struct sockopt * sopt)3684408d548SBill Yuan ip_fw3_ctl_table_show(struct sockopt *sopt)
3694408d548SBill Yuan {
3704408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
3714408d548SBill Yuan struct ipfw3_table_context *table_ctx;
3724408d548SBill Yuan struct radix_node_head *rnh;
3734408d548SBill Yuan struct ipfw_ioc_table *tbl;
3744408d548SBill Yuan void *data;
3754408d548SBill Yuan int size;
3764408d548SBill Yuan
3774408d548SBill Yuan int *id = (int *)sopt->sopt_val;
3784408d548SBill Yuan table_ctx = ctx->table_ctx;
3794408d548SBill Yuan table_ctx += *id;
3804408d548SBill Yuan if (table_ctx->type == 1) {
3814408d548SBill Yuan size = table_ctx->count * sizeof(struct ipfw_ioc_table_ip_entry) +
3824408d548SBill Yuan sizeof(struct ipfw_ioc_table);
3834408d548SBill Yuan if (sopt->sopt_valsize < size) {
3844408d548SBill Yuan /* sopt_val is not big enough */
3854408d548SBill Yuan bzero(sopt->sopt_val, sopt->sopt_valsize);
3864408d548SBill Yuan return 0;
3874408d548SBill Yuan }
3884408d548SBill Yuan data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
3894408d548SBill Yuan tbl = (struct ipfw_ioc_table *)data;
3904408d548SBill Yuan tbl->id = *id;
3914408d548SBill Yuan tbl->type = table_ctx->type;
3924408d548SBill Yuan strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN);
3934408d548SBill Yuan rnh = table_ctx->node;
3944408d548SBill Yuan rnh->rnh_walktree(rnh, dump_table_ip_entry, tbl);
3954408d548SBill Yuan bcopy(tbl, sopt->sopt_val, size);
3964408d548SBill Yuan sopt->sopt_valsize = size;
3974408d548SBill Yuan kfree(data, M_IPFW3_TABLE);
3984408d548SBill Yuan } else if (table_ctx->type == 2) {
3994408d548SBill Yuan size = table_ctx->count * sizeof(struct ipfw_ioc_table_mac_entry) +
4004408d548SBill Yuan sizeof(struct ipfw_ioc_table);
4014408d548SBill Yuan if (sopt->sopt_valsize < size) {
4024408d548SBill Yuan /* sopt_val is not big enough */
4034408d548SBill Yuan bzero(sopt->sopt_val, sopt->sopt_valsize);
4044408d548SBill Yuan return 0;
4054408d548SBill Yuan }
4064408d548SBill Yuan data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
4074408d548SBill Yuan tbl = (struct ipfw_ioc_table *)data;
4084408d548SBill Yuan tbl->id = *id;
4094408d548SBill Yuan tbl->type = table_ctx->type;
4104408d548SBill Yuan strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN);
4114408d548SBill Yuan rnh = table_ctx->node;
4124408d548SBill Yuan rnh->rnh_walktree(rnh, dump_table_mac_entry, tbl);
4134408d548SBill Yuan bcopy(tbl, sopt->sopt_val, size);
4144408d548SBill Yuan sopt->sopt_valsize = size;
4154408d548SBill Yuan kfree(data, M_IPFW3_TABLE);
4164408d548SBill Yuan }
4174408d548SBill Yuan return 0;
4184408d548SBill Yuan }
4194408d548SBill Yuan
4204408d548SBill Yuan /*
4214408d548SBill Yuan * test whether the ip is in the table
4224408d548SBill Yuan */
4234408d548SBill Yuan int
ip_fw3_ctl_table_test(struct sockopt * sopt)4244408d548SBill Yuan ip_fw3_ctl_table_test(struct sockopt *sopt)
4254408d548SBill Yuan {
4264408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
4274408d548SBill Yuan struct ipfw3_table_context *table_ctx;
4284408d548SBill Yuan struct radix_node_head *rnh;
4294408d548SBill Yuan struct ipfw_ioc_table *tbl;
4304408d548SBill Yuan
4314408d548SBill Yuan tbl = (struct ipfw_ioc_table *)sopt->sopt_val;
4324408d548SBill Yuan table_ctx = ctx->table_ctx;
4334408d548SBill Yuan table_ctx += tbl->id;
4344408d548SBill Yuan
4354408d548SBill Yuan if (table_ctx->type != tbl->type)
4364408d548SBill Yuan goto done;
4374408d548SBill Yuan
4384408d548SBill Yuan rnh = table_ctx->node;
4394408d548SBill Yuan if (tbl->type == 1) {
4404408d548SBill Yuan struct sockaddr_in sa;
4414408d548SBill Yuan sa.sin_len = 8;
4424408d548SBill Yuan sa.sin_addr.s_addr = tbl->ip_ent->addr;
4434408d548SBill Yuan
444*d8449084SAaron LI if (rnh->rnh_lookup(&sa, NULL, rnh) != NULL)
4454408d548SBill Yuan return 0;
4464408d548SBill Yuan } else if (tbl->type == 2) {
4474408d548SBill Yuan struct sockaddr sa;
4484408d548SBill Yuan sa.sa_len = 8;
4494408d548SBill Yuan strncpy(sa.sa_data, tbl->mac_ent->addr.octet, 6);
4504408d548SBill Yuan
451*d8449084SAaron LI if (rnh->rnh_lookup(&sa, NULL, rnh) != NULL)
4524408d548SBill Yuan return 0;
4534408d548SBill Yuan } else {
4544408d548SBill Yuan /* XXX TODO */
4554408d548SBill Yuan }
4564408d548SBill Yuan done:
4574408d548SBill Yuan return 1;
4584408d548SBill Yuan }
4594408d548SBill Yuan
4604408d548SBill Yuan /*
4614408d548SBill Yuan * activate the table
4624408d548SBill Yuan */
4634408d548SBill Yuan int
ip_fw3_ctl_table_create(struct sockopt * sopt)4644408d548SBill Yuan ip_fw3_ctl_table_create(struct sockopt *sopt)
4654408d548SBill Yuan {
4664408d548SBill Yuan struct netmsg_table tbmsg;
4674408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg));
4684408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val;
4694408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
4704408d548SBill Yuan 0, table_create_dispatch);
4714408d548SBill Yuan netisr_domsg(&tbmsg.base, 0);
4724408d548SBill Yuan return tbmsg.retval;
4734408d548SBill Yuan }
4744408d548SBill Yuan
4754408d548SBill Yuan /*
4764408d548SBill Yuan * deactivate the table
4774408d548SBill Yuan */
4784408d548SBill Yuan int
ip_fw3_ctl_table_delete(struct sockopt * sopt)4794408d548SBill Yuan ip_fw3_ctl_table_delete(struct sockopt *sopt)
4804408d548SBill Yuan {
4814408d548SBill Yuan struct netmsg_table tbmsg;
4824408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg));
4834408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val;
4844408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
4854408d548SBill Yuan 0, table_delete_dispatch);
4864408d548SBill Yuan netisr_domsg(&tbmsg.base, 0);
4874408d548SBill Yuan return tbmsg.retval;
4884408d548SBill Yuan }
4894408d548SBill Yuan
4904408d548SBill Yuan /*
4914408d548SBill Yuan * append an item into the table
4924408d548SBill Yuan */
4934408d548SBill Yuan int
ip_fw3_ctl_table_append(struct sockopt * sopt)4944408d548SBill Yuan ip_fw3_ctl_table_append(struct sockopt *sopt)
4954408d548SBill Yuan {
4964408d548SBill Yuan struct netmsg_table tbmsg;
4974408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg));
4984408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val;
4994408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
5004408d548SBill Yuan 0, table_append_dispatch);
5014408d548SBill Yuan netisr_domsg(&tbmsg.base, 0);
5024408d548SBill Yuan return tbmsg.retval;
5034408d548SBill Yuan }
5044408d548SBill Yuan
5054408d548SBill Yuan /*
5064408d548SBill Yuan * rename an table
5074408d548SBill Yuan */
5084408d548SBill Yuan int
ip_fw3_ctl_table_rename(struct sockopt * sopt)5094408d548SBill Yuan ip_fw3_ctl_table_rename(struct sockopt *sopt)
5104408d548SBill Yuan {
5114408d548SBill Yuan struct netmsg_table tbmsg;
5124408d548SBill Yuan bzero(&tbmsg,sizeof(tbmsg));
5134408d548SBill Yuan tbmsg.ioc_table = sopt->sopt_val;
5144408d548SBill Yuan netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
5154408d548SBill Yuan 0, table_rename_dispatch);
5164408d548SBill Yuan netisr_domsg(&tbmsg.base, 0);
5174408d548SBill Yuan return tbmsg.retval;
5184408d548SBill Yuan }
5194408d548SBill Yuan
5204408d548SBill Yuan /*
5214408d548SBill Yuan * sockopt handler
5224408d548SBill Yuan */
5234408d548SBill Yuan int
ip_fw3_ctl_table_sockopt(struct sockopt * sopt)5244408d548SBill Yuan ip_fw3_ctl_table_sockopt(struct sockopt *sopt)
5254408d548SBill Yuan {
5264408d548SBill Yuan int error = 0;
5274408d548SBill Yuan switch (sopt->sopt_name) {
5284408d548SBill Yuan case IP_FW_TABLE_CREATE:
5294408d548SBill Yuan error = ip_fw3_ctl_table_create(sopt);
5304408d548SBill Yuan break;
5314408d548SBill Yuan case IP_FW_TABLE_DELETE:
5324408d548SBill Yuan error = ip_fw3_ctl_table_delete(sopt);
5334408d548SBill Yuan break;
5344408d548SBill Yuan case IP_FW_TABLE_APPEND:
5354408d548SBill Yuan error = ip_fw3_ctl_table_append(sopt);
5364408d548SBill Yuan break;
5374408d548SBill Yuan case IP_FW_TABLE_REMOVE:
5384408d548SBill Yuan error = ip_fw3_ctl_table_remove(sopt);
5394408d548SBill Yuan break;
5404408d548SBill Yuan case IP_FW_TABLE_LIST:
5414408d548SBill Yuan error = ip_fw3_ctl_table_list(sopt);
5424408d548SBill Yuan break;
5434408d548SBill Yuan case IP_FW_TABLE_FLUSH:
5444408d548SBill Yuan error = ip_fw3_ctl_table_flush(sopt);
5454408d548SBill Yuan break;
5464408d548SBill Yuan case IP_FW_TABLE_SHOW:
5474408d548SBill Yuan error = ip_fw3_ctl_table_show(sopt);
5484408d548SBill Yuan break;
5494408d548SBill Yuan case IP_FW_TABLE_TEST:
5504408d548SBill Yuan error = ip_fw3_ctl_table_test(sopt);
5514408d548SBill Yuan break;
5524408d548SBill Yuan case IP_FW_TABLE_RENAME:
5534408d548SBill Yuan error = ip_fw3_ctl_table_rename(sopt);
5544408d548SBill Yuan break;
5554408d548SBill Yuan default:
5564408d548SBill Yuan kprintf("ipfw table invalid socket option %d\n",
5574408d548SBill Yuan sopt->sopt_name);
5584408d548SBill Yuan }
5594408d548SBill Yuan return error;
5604408d548SBill Yuan }
5614408d548SBill Yuan
562de23f38fSBill Yuan /*
563de23f38fSBill Yuan * it will be invoked during init of ipfw3
564de23f38fSBill Yuan * this function will prepare the tables
565de23f38fSBill Yuan */
566de23f38fSBill Yuan void
ip_fw3_table_init_dispatch(netmsg_t nmsg)567de23f38fSBill Yuan ip_fw3_table_init_dispatch(netmsg_t nmsg)
5684408d548SBill Yuan {
5694408d548SBill Yuan struct ipfw3_context *ctx = fw3_ctx[mycpuid];
5704408d548SBill Yuan ctx->table_ctx = kmalloc(sizeof(struct ipfw3_table_context) * IPFW_TABLES_MAX,
5714408d548SBill Yuan M_IPFW3_TABLE, M_WAITOK | M_ZERO);
5724408d548SBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
5734408d548SBill Yuan }
5744408d548SBill Yuan
5754408d548SBill Yuan void
ip_fw3_table_fini_dispatch(netmsg_t nmsg)576de23f38fSBill Yuan ip_fw3_table_fini_dispatch(netmsg_t nmsg)
5774408d548SBill Yuan {
5784408d548SBill Yuan struct ipfw3_table_context *table_ctx, *tmp_table;
579de23f38fSBill Yuan int id;
580de23f38fSBill Yuan table_ctx = fw3_ctx[mycpuid]->table_ctx;
5814408d548SBill Yuan tmp_table = table_ctx;
5824408d548SBill Yuan for (id = 0; id < IPFW_TABLES_MAX; id++, table_ctx++) {
5830d7b85c8SAaron LI rn_flush(table_ctx->node, flush_table_entry);
5840d7b85c8SAaron LI /* XXX: should free the tree: rn_freehead(table_ctx->node) */
5854408d548SBill Yuan }
5864408d548SBill Yuan kfree(tmp_table, M_IPFW3_TABLE);
587de23f38fSBill Yuan
588de23f38fSBill Yuan netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
5894408d548SBill Yuan }
5904408d548SBill Yuan
591de23f38fSBill Yuan
5924408d548SBill Yuan void
ip_fw3_table_fini(void)593de23f38fSBill Yuan ip_fw3_table_fini(void)
5944408d548SBill Yuan {
595de23f38fSBill Yuan struct netmsg_base msg;
596de23f38fSBill Yuan
597de23f38fSBill Yuan netmsg_init(&msg, NULL, &curthread->td_msgport,
598de23f38fSBill Yuan 0, ip_fw3_table_fini_dispatch);
599de23f38fSBill Yuan
600de23f38fSBill Yuan netisr_domsg(&msg, 0);
601de23f38fSBill Yuan }
602de23f38fSBill Yuan
603de23f38fSBill Yuan void
ip_fw3_table_init(void)604de23f38fSBill Yuan ip_fw3_table_init(void)
605de23f38fSBill Yuan {
606de23f38fSBill Yuan struct netmsg_base msg;
607de23f38fSBill Yuan
608de23f38fSBill Yuan ip_fw3_ctl_table_ptr = ip_fw3_ctl_table_sockopt;
609de23f38fSBill Yuan netmsg_init(&msg, NULL, &curthread->td_msgport,
610de23f38fSBill Yuan 0, ip_fw3_table_init_dispatch);
611de23f38fSBill Yuan netisr_domsg(&msg, 0);
612de23f38fSBill Yuan }
613de23f38fSBill Yuan
614de23f38fSBill Yuan
615de23f38fSBill Yuan void
ip_fw3_table_modevent(int type)616de23f38fSBill Yuan ip_fw3_table_modevent(int type)
617de23f38fSBill Yuan {
618de23f38fSBill Yuan switch (type) {
619de23f38fSBill Yuan case MOD_LOAD:
620de23f38fSBill Yuan ip_fw3_table_init();
621de23f38fSBill Yuan break;
622de23f38fSBill Yuan case MOD_UNLOAD:
623de23f38fSBill Yuan ip_fw3_table_fini();
624de23f38fSBill Yuan break;
625de23f38fSBill Yuan }
6264408d548SBill Yuan }
627