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