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