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