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