1 /*
2  * Copyright (c) 2015 -2018 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Bill Yuan <bycn82@dragonflybsd.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/kernel.h>
42 #include <sys/proc.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/sysctl.h>
46 #include <sys/syslog.h>
47 #include <sys/ucred.h>
48 #include <sys/in_cksum.h>
49 #include <sys/lock.h>
50 #include <sys/thread2.h>
51 #include <sys/mplock2.h>
52 
53 #include <net/if.h>
54 #include <net/route.h>
55 #include <net/pfil.h>
56 #include <net/netmsg2.h>
57 #include <net/ethernet.h>
58 
59 #include <netinet/in.h>
60 #include <netinet/in_systm.h>
61 #include <netinet/in_var.h>
62 #include <netinet/in_pcb.h>
63 #include <netinet/ip.h>
64 #include <netinet/ip_var.h>
65 #include <netinet/ip_icmp.h>
66 #include <netinet/tcp.h>
67 #include <netinet/tcp_timer.h>
68 #include <netinet/tcp_var.h>
69 #include <netinet/tcpip.h>
70 #include <netinet/udp.h>
71 #include <netinet/udp_var.h>
72 #include <netinet/ip_divert.h>
73 #include <netinet/if_ether.h>
74 
75 #include <net/ipfw3/ip_fw.h>
76 #include <net/ipfw3_basic/ip_fw3_table.h>
77 
78 MALLOC_DEFINE(M_IPFW3_TABLE, "IPFW3_TABLE", "mem for ip_fw3 table");
79 
80 extern struct ipfw3_context	*fw3_ctx[MAXCPU];
81 
82 /*
83  * activate/create the table by setup the type and reset counts.
84  */
85 static void
86 table_create_dispatch(netmsg_t nmsg)
87 {
88 	struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
89 	struct ipfw_ioc_table *ioc_table;
90 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
91 	struct ipfw3_table_context *table_ctx;
92 	ioc_table = tbmsg->ioc_table;
93 	int id = ioc_table->id;
94 
95 	table_ctx = ctx->table_ctx;
96 	table_ctx += id;
97 	table_ctx->type = ioc_table->type;
98 	table_ctx->count = 0;
99 	strlcpy(table_ctx->name , ioc_table->name, IPFW_TABLE_NAME_LEN);
100 	if (table_ctx->type == 1) {
101 		rn_inithead((void **)&table_ctx->mask, NULL, 0);
102 		rn_inithead((void **)&table_ctx->node, table_ctx->mask, 32);
103         } else if (table_ctx->type == 2) {
104                 rn_inithead((void **)&table_ctx->mask, NULL, 0);
105 		rn_inithead((void **)&table_ctx->node, table_ctx->mask, 48);
106         } else {
107                 goto done;
108         }
109 done:
110 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
111 }
112 
113 /*
114  * clean the table, especially the node
115  */
116 static void
117 table_delete_dispatch(netmsg_t nmsg)
118 {
119 	struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
120 	struct ipfw_ioc_table *ioc_tbl;
121 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
122 	struct ipfw3_table_context *table_ctx;
123 	struct radix_node_head *rnh;
124 
125 	ioc_tbl = tbmsg->ioc_table;
126 	table_ctx = ctx->table_ctx;
127 	table_ctx += ioc_tbl->id;
128 	table_ctx->count = 0;
129 
130         if (table_ctx->type == 1) {
131                 rnh = table_ctx->node;
132                 rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh);
133         } else if (table_ctx->type == 2) {
134                 rnh = table_ctx->node;
135                 rnh->rnh_walktree(rnh, flush_table_mac_entry, rnh);
136         }
137 	table_ctx->type = 0;
138 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
139 }
140 
141 static void
142 table_append_dispatch(netmsg_t nmsg)
143 {
144 	struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
145 	struct ipfw_ioc_table *ioc_tbl;
146 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
147 	struct ipfw3_table_context *table_ctx;
148 	struct radix_node_head *rnh;
149 
150 	uint8_t mlen;
151 
152 	ioc_tbl = tbmsg->ioc_table;
153 	table_ctx = ctx->table_ctx;
154 	table_ctx += ioc_tbl->id;
155 	if (table_ctx->type != ioc_tbl->type)
156 		goto done;
157 
158         if (table_ctx->type == 1 ) {
159                 struct table_ip_entry *ent;
160 
161                 rnh = table_ctx->node;
162                 ent = kmalloc(sizeof(struct table_ip_entry),
163                                 M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
164 
165                 if (ent == NULL)
166                         return;
167                 mlen = ioc_tbl->ip_ent->masklen;
168                 ent->addr.sin_len = ent->mask.sin_len = 8;
169                 ent->mask.sin_addr.s_addr = htonl(~((1 << (32 - mlen)) - 1));
170                 ent->addr.sin_addr.s_addr = ioc_tbl->ip_ent->addr &
171                                                 ent->mask.sin_addr.s_addr;
172 
173                 if (rnh->rnh_addaddr((char *)&ent->addr,
174                                 (char *)&ent->mask, rnh,
175                                 (void *)ent->rn) != NULL) {
176                         table_ctx->count++;
177                 }
178         } else if (table_ctx->type == 2 ) {
179                 struct table_mac_entry *ent;
180 
181                 rnh = table_ctx->node;
182                 ent = kmalloc(sizeof(struct table_mac_entry),
183                                 M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
184                 if (ent == NULL)
185                         return;
186                 ent->addr.sa_len = 8;
187                 strncpy(ent->addr.sa_data, ioc_tbl->mac_ent->addr.octet, 6);
188 
189                 if (rnh->rnh_addaddr((char *)&ent->addr,
190                                 NULL, rnh, (void *)ent->rn) != NULL) {
191                        table_ctx->count++;
192                 }
193         }
194 
195 done:
196 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
197 }
198 
199 static void
200 table_remove_dispatch(netmsg_t nmsg)
201 {
202 	struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
203 	struct ipfw_ioc_table *ioc_tbl;
204 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
205 	struct ipfw3_table_context *table_ctx;
206 	struct radix_node_head *rnh;
207 	struct table_entry *ent;
208 	struct sockaddr_in sa, mask;
209 	in_addr_t addr;
210 	uint8_t mlen;
211 
212 	ioc_tbl = tbmsg->ioc_table;
213 	table_ctx = ctx->table_ctx;
214 	table_ctx += ioc_tbl->id;
215 	if (table_ctx->type != ioc_tbl->type)
216 		goto done;
217 
218 	rnh = table_ctx->node;
219 
220 	mlen = ioc_tbl->ip_ent->masklen;
221 	addr = ioc_tbl->ip_ent->addr;
222 
223 	sa.sin_len = mask.sin_len = 8;
224 	mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0);
225 	sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr;
226 
227 	ent = (struct table_entry *)rnh->rnh_deladdr((char *)&sa, (char *)&mask, rnh);
228 	if (ent != NULL) {
229 		table_ctx->count--;
230 		kfree(ent, M_IPFW3_TABLE);
231 	}
232 done:
233 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
234 }
235 
236 int
237 flush_table_ip_entry(struct radix_node *rn, void *arg)
238 {
239 	struct radix_node_head *rnh = arg;
240 	struct table_ip_entry *ent;
241 
242 	ent = (struct table_ip_entry *)
243 		rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
244 	if (ent != NULL)
245 		kfree(ent, M_IPFW3_TABLE);
246 	return (0);
247 }
248 
249 int
250 flush_table_mac_entry(struct radix_node *rn, void *arg)
251 {
252 	struct radix_node_head *rnh = arg;
253 	struct table_mac_entry *ent;
254 
255 	ent = (struct table_mac_entry *)
256 		rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh);
257 	if (ent != NULL)
258 		kfree(ent, M_IPFW3_TABLE);
259 	return (0);
260 }
261 
262 static void
263 table_flush_dispatch(netmsg_t nmsg)
264 {
265 	struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
266 	struct ipfw_ioc_table *ioc_tbl;
267 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
268 	struct ipfw3_table_context *table_ctx;
269 	struct radix_node_head *rnh;
270 
271 	ioc_tbl = tbmsg->ioc_table;
272 	table_ctx = ctx->table_ctx;
273 	table_ctx += ioc_tbl->id;
274 	rnh = table_ctx->node;
275 	table_ctx->count = 0;
276 
277 	rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh);
278 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
279 }
280 
281 /*
282  * rename the table
283  */
284 static void
285 table_rename_dispatch(netmsg_t nmsg)
286 {
287 	struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg;
288 	struct ipfw_ioc_table *ioc_tbl;
289 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
290 	struct ipfw3_table_context *table_ctx;
291 
292 	ioc_tbl = tbmsg->ioc_table;
293 	table_ctx = ctx->table_ctx;
294 	table_ctx += ioc_tbl->id;
295 	strlcpy(table_ctx->name, ioc_tbl->name, IPFW_TABLE_NAME_LEN);
296 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
297 }
298 
299 /*
300  * list all the overview information about each table
301  */
302 int
303 ip_fw3_ctl_table_list(struct sockopt *sopt)
304 {
305 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
306 	struct ipfw3_table_context *table_ctx = ctx->table_ctx;
307 	struct ipfw_ioc_table *ioc_table;
308 	int i, error = 0, size;
309 
310 	size = IPFW_TABLES_MAX * sizeof(struct ipfw_ioc_table);
311 	if (sopt->sopt_valsize < size) {
312 		/* sopt_val is not big enough */
313 		bzero(sopt->sopt_val, sopt->sopt_valsize);
314 		return 0;
315 	}
316 	ioc_table = (struct ipfw_ioc_table *)sopt->sopt_val;
317 	for (i = 0; i < IPFW_TABLES_MAX; i++, ioc_table++, table_ctx++) {
318 		ioc_table->id = i;
319 		ioc_table->type = table_ctx->type;
320 		ioc_table->count = table_ctx->count;
321 		strlcpy(ioc_table->name, table_ctx->name, IPFW_TABLE_NAME_LEN);
322 	}
323 	sopt->sopt_valsize = size;
324 	return error;
325 }
326 
327 /*
328  * remove an item from the table
329  */
330 int
331 ip_fw3_ctl_table_remove(struct sockopt *sopt)
332 {
333 	struct netmsg_table tbmsg;
334 	bzero(&tbmsg,sizeof(tbmsg));
335 	tbmsg.ioc_table = sopt->sopt_val;
336 	netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
337 			0, table_remove_dispatch);
338 	netisr_domsg(&tbmsg.base, 0);
339 	return tbmsg.retval;
340 }
341 
342 /*
343  * flush everything inside the table
344  */
345 int
346 ip_fw3_ctl_table_flush(struct sockopt *sopt)
347 {
348 	struct netmsg_table tbmsg;
349 	bzero(&tbmsg,sizeof(tbmsg));
350 	tbmsg.ioc_table = sopt->sopt_val;
351 	netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
352 			0, table_flush_dispatch);
353 	netisr_domsg(&tbmsg.base, 0);
354 	return tbmsg.retval;
355 }
356 
357 /*
358  * dump the entries into the ioc_table
359  */
360 int
361 dump_table_ip_entry(struct radix_node *rn, void *arg)
362 {
363 	struct table_ip_entry *ent = (struct table_ip_entry *)rn;
364 	struct ipfw_ioc_table_ip_entry *ioc_ent;
365 	struct ipfw_ioc_table *tbl = arg;
366         struct sockaddr_in *addr, *mask;
367 
368         addr = &ent->addr;
369         mask = &ent->mask;
370 
371 	ioc_ent = &tbl->ip_ent[tbl->count];
372 	if (in_nullhost(mask->sin_addr))
373 		ioc_ent->masklen = 0;
374 	else
375 		ioc_ent->masklen = 33 - ffs(ntohl(mask->sin_addr.s_addr));
376 	ioc_ent->addr = addr->sin_addr.s_addr;
377 	tbl->count++;
378 	return (0);
379 }
380 
381 int
382 dump_table_mac_entry(struct radix_node *rn, void *arg)
383 {
384 	struct table_mac_entry *ent = (struct table_mac_entry *)rn;
385 	struct ipfw_ioc_table_mac_entry *ioc_ent;
386 	struct ipfw_ioc_table *tbl = arg;
387 	ioc_ent = &tbl->mac_ent[tbl->count];
388         strncpy(ioc_ent->addr.octet, ent->addr.sa_data, 6);
389 	tbl->count++;
390 	return (0);
391 }
392 
393 /*
394  * get and display all items in the table
395  */
396 int
397 ip_fw3_ctl_table_show(struct sockopt *sopt)
398 {
399 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
400 	struct ipfw3_table_context *table_ctx;
401 	struct radix_node_head *rnh;
402 	struct ipfw_ioc_table *tbl;
403 	void *data;
404 	int size;
405 
406 	int *id = (int *)sopt->sopt_val;
407 	table_ctx = ctx->table_ctx;
408 	table_ctx += *id;
409         if (table_ctx->type == 1) {
410                 size = table_ctx->count * sizeof(struct ipfw_ioc_table_ip_entry) +
411                                 sizeof(struct ipfw_ioc_table);
412                 if (sopt->sopt_valsize < size) {
413                         /* sopt_val is not big enough */
414                         bzero(sopt->sopt_val, sopt->sopt_valsize);
415                         return 0;
416                 }
417                 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
418                 tbl = (struct ipfw_ioc_table *)data;
419                 tbl->id = *id;
420                 tbl->type = table_ctx->type;
421 		strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN);
422                 rnh = table_ctx->node;
423                 rnh->rnh_walktree(rnh, dump_table_ip_entry, tbl);
424                 bcopy(tbl, sopt->sopt_val, size);
425                 sopt->sopt_valsize = size;
426                 kfree(data, M_IPFW3_TABLE);
427         } else if (table_ctx->type == 2) {
428                 size = table_ctx->count * sizeof(struct ipfw_ioc_table_mac_entry) +
429                                 sizeof(struct ipfw_ioc_table);
430                 if (sopt->sopt_valsize < size) {
431                         /* sopt_val is not big enough */
432                         bzero(sopt->sopt_val, sopt->sopt_valsize);
433                         return 0;
434                 }
435                 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO);
436                 tbl = (struct ipfw_ioc_table *)data;
437                 tbl->id = *id;
438                 tbl->type = table_ctx->type;
439 		strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN);
440                 rnh = table_ctx->node;
441                 rnh->rnh_walktree(rnh, dump_table_mac_entry, tbl);
442                 bcopy(tbl, sopt->sopt_val, size);
443                 sopt->sopt_valsize = size;
444                 kfree(data, M_IPFW3_TABLE);
445         }
446 	return 0;
447 }
448 
449 /*
450  * test whether the ip is in the table
451  */
452 int
453 ip_fw3_ctl_table_test(struct sockopt *sopt)
454 {
455 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
456 	struct ipfw3_table_context *table_ctx;
457 	struct radix_node_head *rnh;
458 	struct ipfw_ioc_table *tbl;
459 
460 	tbl = (struct ipfw_ioc_table *)sopt->sopt_val;
461 	table_ctx = ctx->table_ctx;
462 	table_ctx += tbl->id;
463 
464         if (table_ctx->type != tbl->type)
465                 goto done;
466 
467         rnh = table_ctx->node;
468         if (tbl->type == 1) {
469                 struct sockaddr_in sa;
470                 sa.sin_len = 8;
471                 sa.sin_addr.s_addr = tbl->ip_ent->addr;
472 
473                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
474                         return 0;
475         } else if (tbl->type == 2) {
476                 struct sockaddr sa;
477                 sa.sa_len = 8;
478                 strncpy(sa.sa_data, tbl->mac_ent->addr.octet, 6);
479 
480                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
481                         return 0;
482         } else {
483                 /* XXX TODO */
484         }
485 done:
486 	return 1;
487 }
488 
489 /*
490  * activate the table
491  */
492 int
493 ip_fw3_ctl_table_create(struct sockopt *sopt)
494 {
495 	struct netmsg_table tbmsg;
496 	bzero(&tbmsg,sizeof(tbmsg));
497 	tbmsg.ioc_table = sopt->sopt_val;
498 	netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
499 			0, table_create_dispatch);
500 	netisr_domsg(&tbmsg.base, 0);
501 	return tbmsg.retval;
502 }
503 
504 /*
505  * deactivate the table
506  */
507 int
508 ip_fw3_ctl_table_delete(struct sockopt *sopt)
509 {
510 	struct netmsg_table tbmsg;
511 	bzero(&tbmsg,sizeof(tbmsg));
512 	tbmsg.ioc_table = sopt->sopt_val;
513 	netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
514 			0, table_delete_dispatch);
515 	netisr_domsg(&tbmsg.base, 0);
516 	return tbmsg.retval;
517 }
518 
519 /*
520  * append an item into the table
521  */
522 int
523 ip_fw3_ctl_table_append(struct sockopt *sopt)
524 {
525 	struct netmsg_table tbmsg;
526 	bzero(&tbmsg,sizeof(tbmsg));
527 	tbmsg.ioc_table = sopt->sopt_val;
528 	netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
529 			0, table_append_dispatch);
530 	netisr_domsg(&tbmsg.base, 0);
531 	return tbmsg.retval;
532 }
533 
534 /*
535  * rename an table
536  */
537 int
538 ip_fw3_ctl_table_rename(struct sockopt *sopt)
539 {
540 	struct netmsg_table tbmsg;
541 	bzero(&tbmsg,sizeof(tbmsg));
542 	tbmsg.ioc_table = sopt->sopt_val;
543 	netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport,
544 			0, table_rename_dispatch);
545 	netisr_domsg(&tbmsg.base, 0);
546 	return tbmsg.retval;
547 }
548 
549 /*
550  * sockopt handler
551  */
552 int
553 ip_fw3_ctl_table_sockopt(struct sockopt *sopt)
554 {
555 	int error = 0;
556 	switch (sopt->sopt_name) {
557 		case IP_FW_TABLE_CREATE:
558 			error = ip_fw3_ctl_table_create(sopt);
559 			break;
560 		case IP_FW_TABLE_DELETE:
561 			error = ip_fw3_ctl_table_delete(sopt);
562 			break;
563 		case IP_FW_TABLE_APPEND:
564 			error = ip_fw3_ctl_table_append(sopt);
565 			break;
566 		case IP_FW_TABLE_REMOVE:
567 			error = ip_fw3_ctl_table_remove(sopt);
568 			break;
569 		case IP_FW_TABLE_LIST:
570 			error = ip_fw3_ctl_table_list(sopt);
571 			break;
572 		case IP_FW_TABLE_FLUSH:
573 			error = ip_fw3_ctl_table_flush(sopt);
574 			break;
575 		case IP_FW_TABLE_SHOW:
576 			error = ip_fw3_ctl_table_show(sopt);
577 			break;
578 		case IP_FW_TABLE_TEST:
579 			error = ip_fw3_ctl_table_test(sopt);
580 			break;
581 		case IP_FW_TABLE_RENAME:
582 			error = ip_fw3_ctl_table_rename(sopt);
583 			break;
584 		default:
585 			kprintf("ipfw table invalid socket option %d\n",
586 				sopt->sopt_name);
587 	}
588 	return error;
589 }
590 
591 static void
592 table_init_ctx_dispatch(netmsg_t nmsg)
593 {
594 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
595 	ctx->table_ctx = kmalloc(sizeof(struct ipfw3_table_context) * IPFW_TABLES_MAX,
596 			M_IPFW3_TABLE, M_WAITOK | M_ZERO);
597 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
598 }
599 
600 /*
601  * release the memory of the tables
602  */
603 void
604 table_fini(void)
605 {
606 	struct ipfw3_table_context *table_ctx, *tmp_table;
607 	struct radix_node_head *rnh;
608 	int cpu, id;
609 	for (cpu = 0; cpu < ncpus; cpu++) {
610 		table_ctx = fw3_ctx[cpu]->table_ctx;
611 		tmp_table = table_ctx;
612 		for (id = 0; id < IPFW_TABLES_MAX; id++, table_ctx++) {
613 			if (table_ctx->type == 1) {
614 				rnh = table_ctx->node;
615 				rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh);
616 			} else if (table_ctx->type == 2) {
617 				rnh = table_ctx->node;
618 				rnh->rnh_walktree(rnh, flush_table_mac_entry, rnh);
619 			}
620 		}
621 		kfree(tmp_table, M_IPFW3_TABLE);
622 	}
623 }
624 
625 /*
626  * it will be invoked during init of ipfw3
627  * this function will prepare the tables
628  */
629 void
630 table_init_dispatch(netmsg_t nmsg)
631 {
632 	int error = 0;
633 	struct netmsg_base nmsg_base;
634 	bzero(&nmsg_base, sizeof(nmsg_base));
635 	netmsg_init(&nmsg_base, NULL, &curthread->td_msgport,
636 			0, table_init_ctx_dispatch);
637 	netisr_domsg(&nmsg_base, 0);
638 	lwkt_replymsg(&nmsg->lmsg, error);
639 }
640