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