1 /*
2  * Copyright (c) 2014 - 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 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/mbuf.h>
39 #include <sys/socketvar.h>
40 #include <sys/sysctl.h>
41 #include <sys/systimer.h>
42 #include <sys/in_cksum.h>
43 #include <sys/systm.h>
44 #include <sys/proc.h>
45 #include <sys/socket.h>
46 #include <sys/syslog.h>
47 #include <sys/ucred.h>
48 #include <sys/lock.h>
49 
50 #include <net/if.h>
51 #include <net/ethernet.h>
52 #include <net/netmsg2.h>
53 #include <net/netisr2.h>
54 #include <net/route.h>
55 
56 #include <netinet/ip.h>
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_var.h>
62 #include <netinet/ip_icmp.h>
63 #include <netinet/tcp.h>
64 #include <netinet/tcp_timer.h>
65 #include <netinet/tcp_var.h>
66 #include <netinet/tcpip.h>
67 #include <netinet/udp.h>
68 #include <netinet/udp_var.h>
69 #include <netinet/ip_divert.h>
70 #include <netinet/if_ether.h>
71 
72 #include <net/ipfw3/ip_fw.h>
73 #include <net/ipfw3_basic/ip_fw3_state.h>
74 
75 MALLOC_DEFINE(M_IPFW3_STATE, "M_IPFW3_STATE", "mem for ipfw3 states");
76 
77 
78 struct ipfw3_state_context 		*fw3_state_ctx[MAXCPU];
79 extern struct ipfw3_context		*fw3_ctx[MAXCPU];
80 extern ip_fw_ctl_t 			*ip_fw3_ctl_state_ptr;
81 
82 static struct callout 		ip_fw3_state_cleanup_callout;
83 static int 			sysctl_var_cleanup_interval = 1;
84 
85 static int 			sysctl_var_state_max_tcp_in = 4096;
86 static int 			sysctl_var_state_max_udp_in = 4096;
87 static int 			sysctl_var_state_max_icmp_in = 10;
88 
89 static int 			sysctl_var_state_max_tcp_out = 4096;
90 static int 			sysctl_var_state_max_udp_out = 4096;
91 static int 			sysctl_var_state_max_icmp_out = 10;
92 
93 static int 			sysctl_var_icmp_timeout = 10;
94 static int 			sysctl_var_tcp_timeout = 60;
95 static int 			sysctl_var_udp_timeout = 30;
96 
97 
98 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw3_basic, CTLFLAG_RW, 0, "Firewall Basic");
99 
100 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_tcp_in, CTLFLAG_RW,
101 		&sysctl_var_state_max_tcp_in, 0, "maximum of tcp state in");
102 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_tcp_out, CTLFLAG_RW,
103 		&sysctl_var_state_max_tcp_out, 0, "maximum of tcp state out");
104 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_udp_in, CTLFLAG_RW,
105 		&sysctl_var_state_max_udp_in, 0, "maximum of udp state in");
106 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_udp_out, CTLFLAG_RW,
107 		&sysctl_var_state_max_udp_out, 0, "maximum of udp state out");
108 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_icmp_in, CTLFLAG_RW,
109 		&sysctl_var_state_max_icmp_in, 0, "maximum of icmp state in");
110 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_icmp_out, CTLFLAG_RW,
111 		&sysctl_var_state_max_icmp_out, 0, "maximum of icmp state out");
112 
113 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, cleanup_interval, CTLFLAG_RW,
114 		&sysctl_var_cleanup_interval, 0,
115 		"default state expiry check interval");
116 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, icmp_timeout, CTLFLAG_RW,
117 		&sysctl_var_icmp_timeout, 0, "default icmp state life time");
118 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, tcp_timeout, CTLFLAG_RW,
119 		&sysctl_var_tcp_timeout, 0, "default tcp state life time");
120 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, udp_timeout, CTLFLAG_RW,
121 		&sysctl_var_udp_timeout, 0, "default udp state life time");
122 
123 RB_GENERATE(fw3_state_tree, ipfw3_state, entries, ip_fw3_state_cmp);
124 
125 
126 int
127 ip_fw3_state_cmp(struct ipfw3_state *s1, struct ipfw3_state *s2)
128 {
129 	if (s1->src_addr > s2->src_addr)
130 		return 1;
131 	if (s1->src_addr < s2->src_addr)
132 		return -1;
133 
134 	if (s1->dst_addr > s2->dst_addr)
135 		return 1;
136 	if (s1->dst_addr < s2->dst_addr)
137 		return -1;
138 
139 	if (s1->src_port > s2->src_port)
140 		return 1;
141 	if (s1->src_port < s2->src_port)
142 		return -1;
143 
144 	if (s1->dst_port > s2->dst_port)
145 		return 1;
146 	if (s1->dst_port < s2->dst_port)
147 		return -1;
148 
149 	return 0;
150 }
151 
152 void
153 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
154 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
155 {
156 	/* state_tree 1 same direction, state_tree2 opposite direction */
157 	struct fw3_state_tree *state_tree1, *state_tree2;
158 	struct ip *ip = mtod((*args)->m, struct ip *);
159 	struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
160 	struct ipfw3_state *s, *k, key;
161 
162 	k = &key;
163 	memset(k, 0, LEN_FW3_STATE);
164 
165 	if ((*args)->oif == NULL) {
166 		switch (ip->ip_p) {
167 		case IPPROTO_TCP:
168 			state_tree1 = &state_ctx->rb_tcp_in;
169 			state_tree2 = &state_ctx->rb_tcp_out;
170 		break;
171 		case IPPROTO_UDP:
172 			state_tree1 = &state_ctx->rb_udp_in;
173 			state_tree2 = &state_ctx->rb_udp_out;
174 		break;
175 		case IPPROTO_ICMP:
176 			state_tree1 = &state_ctx->rb_icmp_in;
177 			state_tree2 = &state_ctx->rb_icmp_out;
178 		break;
179 		default:
180 			goto oops;
181 		}
182 	} else {
183 		switch (ip->ip_p) {
184 		case IPPROTO_TCP:
185 			state_tree1 = &state_ctx->rb_tcp_out;
186 			state_tree2 = &state_ctx->rb_tcp_in;
187 		break;
188 		case IPPROTO_UDP:
189 			state_tree1 = &state_ctx->rb_udp_out;
190 			state_tree2 = &state_ctx->rb_udp_in;
191 		break;
192 		case IPPROTO_ICMP:
193 			state_tree1 = &state_ctx->rb_icmp_out;
194 			state_tree2 = &state_ctx->rb_icmp_in;
195 		break;
196 		default:
197 			goto oops;
198 		}
199 	}
200 
201 	k->src_addr = (*args)->f_id.src_ip;
202 	k->dst_addr = (*args)->f_id.dst_ip;
203 	k->src_port = (*args)->f_id.src_port;
204 	k->dst_port = (*args)->f_id.dst_port;
205 	s = RB_FIND(fw3_state_tree, state_tree1, k);
206 	if (s != NULL) {
207 		(*f)->pcnt++;
208 		(*f)->bcnt += ip_len;
209 		(*f)->timestamp = time_second;
210 		*f = s->stub;
211 		s->timestamp = time_uptime;
212 		*cmd_val = IP_FW_PASS;
213 		*cmd_ctl = IP_FW_CTL_CHK_STATE;
214 		return;
215 	}
216 	k->dst_addr = (*args)->f_id.src_ip;
217 	k->src_addr = (*args)->f_id.dst_ip;
218 	k->dst_port = (*args)->f_id.src_port;
219 	k->src_port = (*args)->f_id.dst_port;
220 	s = RB_FIND(fw3_state_tree, state_tree2, k);
221 	if (s != NULL) {
222 		(*f)->pcnt++;
223 		(*f)->bcnt += ip_len;
224 		(*f)->timestamp = time_second;
225 		*f = s->stub;
226 		s->timestamp = time_uptime;
227 		*cmd_val = IP_FW_PASS;
228 		*cmd_ctl = IP_FW_CTL_CHK_STATE;
229 		return;
230 	}
231 oops:
232 	*cmd_val = IP_FW_NOT_MATCH;
233 	*cmd_ctl = IP_FW_CTL_NEXT;
234 }
235 
236 void
237 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
238 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
239 {
240 	/* state_tree 1 same direction, state_tree2 opposite direction */
241 	struct fw3_state_tree *the_tree = NULL;
242 	struct ip *ip = mtod((*args)->m, struct ip *);
243 	struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
244 	struct ipfw3_state *s, *k, key;
245 	int states_matched = 0, *the_count, the_max;
246 
247 	k = &key;
248 	memset(k, 0, LEN_FW3_STATE);
249 	if ((*args)->oif == NULL) {
250 		switch (ip->ip_p) {
251 		case IPPROTO_TCP:
252 			the_tree = &state_ctx->rb_tcp_in;
253 			the_count = &state_ctx->count_tcp_in;
254 			the_max = sysctl_var_state_max_tcp_in;
255 		break;
256 		case IPPROTO_UDP:
257 			the_tree = &state_ctx->rb_udp_in;
258 			the_count = &state_ctx->count_udp_in;
259 			the_max = sysctl_var_state_max_udp_in;
260 		break;
261 		case IPPROTO_ICMP:
262 			the_tree = &state_ctx->rb_icmp_in;
263 			the_count = &state_ctx->count_icmp_in;
264 			the_max = sysctl_var_state_max_icmp_in;
265 		break;
266 		default:
267 			goto done;
268 		}
269 	} else {
270 		switch (ip->ip_p) {
271 		case IPPROTO_TCP:
272 			the_tree = &state_ctx->rb_tcp_out;
273 			the_count = &state_ctx->count_tcp_out;
274 			the_max = sysctl_var_state_max_tcp_out;
275 		break;
276 		case IPPROTO_UDP:
277 			the_tree = &state_ctx->rb_udp_out;
278 			the_count = &state_ctx->count_udp_out;
279 			the_max = sysctl_var_state_max_udp_out;
280 		break;
281 		case IPPROTO_ICMP:
282 			the_tree = &state_ctx->rb_icmp_out;
283 			the_count = &state_ctx->count_icmp_out;
284 			the_max = sysctl_var_state_max_icmp_out;
285 		break;
286 		default:
287 			goto done;
288 		}
289 	}
290 	*cmd_ctl = IP_FW_CTL_NO;
291 	k->src_addr = (*args)->f_id.src_ip;
292 	k->dst_addr = (*args)->f_id.dst_ip;
293 	k->src_port = (*args)->f_id.src_port;
294 	k->dst_port = (*args)->f_id.dst_port;
295 	/* cmd->arg3 is `limit type` */
296 	if (cmd->arg3 == 0) {
297 		s = RB_FIND(fw3_state_tree, the_tree, k);
298 		if (s != NULL) {
299 			goto done;
300 		}
301 	} else {
302 		RB_FOREACH(s, fw3_state_tree, the_tree) {
303 			if (cmd->arg3 == 1 && s->src_addr == k->src_addr) {
304 				states_matched++;
305 			} else if (cmd->arg3 == 2 && s->src_port == k->src_port) {
306 				states_matched++;
307 			} else if (cmd->arg3 == 3 && s->dst_addr == k->dst_addr) {
308 				states_matched++;
309 			} else if (cmd->arg3 == 4 && s->dst_port == k->dst_port) {
310 				states_matched++;
311 			}
312 		}
313 		if (states_matched >= cmd->arg1) {
314 			goto done;
315 		}
316 	}
317 	if (*the_count <= the_max) {
318 		(*the_count)++;
319 		s = kmalloc(LEN_FW3_STATE, M_IPFW3_STATE,
320 				M_INTWAIT | M_NULLOK | M_ZERO);
321 		s->src_addr = k->src_addr;
322 		s->dst_addr = k->dst_addr;
323 		s->src_port = k->src_port;
324 		s->dst_port = k->dst_port;
325 		s->stub = *f;
326 		s->timestamp = time_uptime;
327 		if (RB_INSERT(fw3_state_tree, the_tree, s)) {
328 			kprintf("oops\n");
329 		}
330 	}
331 done:
332 	*cmd_ctl = IP_FW_CTL_NO;
333 	*cmd_val = IP_FW_MATCH;
334 }
335 
336 void
337 ip_fw3_state_append_dispatch(netmsg_t nmsg)
338 {
339 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
340 }
341 
342 void
343 ip_fw3_state_delete_dispatch(netmsg_t nmsg)
344 {
345 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
346 }
347 
348 int
349 ip_fw3_ctl_state_add(struct sockopt *sopt)
350 {
351 	return 0;
352 }
353 
354 int
355 ip_fw3_ctl_state_delete(struct sockopt *sopt)
356 {
357 	return 0;
358 }
359 
360 void
361 ip_fw3_state_flush_dispatch(netmsg_t nmsg)
362 {
363 	struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
364 	struct ipfw3_state *s, *tmp;
365 
366 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_in, tmp) {
367 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_in, s);
368 		if (s != NULL) {
369 			kfree(s, M_IPFW3_STATE);
370 		}
371 	}
372 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_out, tmp) {
373 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_out, s);
374 		if (s != NULL) {
375 			kfree(s, M_IPFW3_STATE);
376 		}
377 	}
378 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_in, tmp) {
379 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_in, s);
380 		if (s != NULL) {
381 			kfree(s, M_IPFW3_STATE);
382 		}
383 	}
384 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_out, tmp) {
385 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_out, s);
386 		if (s != NULL) {
387 			kfree(s, M_IPFW3_STATE);
388 		}
389 	}
390 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_in, tmp) {
391 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_in, s);
392 		if (s != NULL) {
393 			kfree(s, M_IPFW3_STATE);
394 		}
395 	}
396 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_out, tmp) {
397 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_out, s);
398 		if (s != NULL) {
399 			kfree(s, M_IPFW3_STATE);
400 		}
401 	}
402 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
403 }
404 
405 void
406 ip_fw3_state_flush(struct ip_fw *rule)
407 {
408 	struct netmsg_base msg;
409 	netmsg_init(&msg, NULL, &curthread->td_msgport, 0,
410 			ip_fw3_state_flush_dispatch);
411 	netisr_domsg(&msg, 0);
412 }
413 
414 int
415 ip_fw3_ctl_state_flush(struct sockopt *sopt)
416 {
417 
418 	return 0;
419 }
420 
421 int
422 ip_fw3_ctl_state_get(struct sockopt *sopt)
423 {
424 	struct ipfw3_state_context *state_ctx;
425 	struct ipfw3_state *s;
426 
427 	size_t sopt_size, total_len = 0;
428 	struct ipfw3_ioc_state *ioc;
429 	int ioc_rule_id;
430 
431 	ioc_rule_id = *((int *)(sopt->sopt_val));
432 	sopt_size = sopt->sopt_valsize;
433 	ioc = (struct ipfw3_ioc_state *)sopt->sopt_val;
434 	/* icmp states only in CPU 0 */
435 	int cpu = 0;
436 
437 	/* icmp states */
438 	for (cpu = 0; cpu < ncpus; cpu++) {
439 		state_ctx = fw3_state_ctx[cpu];
440 		RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_icmp_in) {
441 			total_len += LEN_IOC_FW3_STATE;
442 			if (total_len > sopt_size)
443 				goto nospace;
444 			ioc->src_addr.s_addr = ntohl(s->src_addr);
445 			ioc->dst_addr.s_addr = ntohl(s->dst_addr);
446 			ioc->src_port = ntohs(s->src_port);
447 			ioc->dst_port = ntohs(s->dst_port);
448 			ioc->cpu_id = cpu;
449 			ioc->rule_id = s->stub->rulenum;
450 			ioc->proto = IPPROTO_ICMP;
451 			ioc->life = s->timestamp +
452 				sysctl_var_udp_timeout - time_uptime;
453 			ioc++;
454 		}
455 		RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_icmp_out) {
456 			total_len += LEN_IOC_FW3_STATE;
457 			if (total_len > sopt_size)
458 				goto nospace;
459 			ioc->src_addr.s_addr = ntohl(s->src_addr);
460 			ioc->dst_addr.s_addr = ntohl(s->dst_addr);
461 			ioc->src_port = ntohs(s->src_port);
462 			ioc->dst_port = ntohs(s->dst_port);
463 			ioc->cpu_id = cpu;
464 			ioc->rule_id = s->stub->rulenum;
465 			ioc->proto = IPPROTO_ICMP;
466 			ioc->life = s->timestamp +
467 				sysctl_var_udp_timeout - time_uptime;
468 			ioc++;
469 		}
470 		RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_tcp_in) {
471 			total_len += LEN_IOC_FW3_STATE;
472 			if (total_len > sopt_size)
473 				goto nospace;
474 			ioc->src_addr.s_addr = ntohl(s->src_addr);
475 			ioc->dst_addr.s_addr = ntohl(s->dst_addr);
476 			ioc->src_port = ntohs(s->src_port);
477 			ioc->dst_port = ntohs(s->dst_port);
478 			ioc->cpu_id = cpu;
479 			ioc->rule_id = s->stub->rulenum;
480 			ioc->proto = IPPROTO_TCP;
481 			ioc->life = s->timestamp +
482 				sysctl_var_udp_timeout - time_uptime;
483 			ioc++;
484 		}
485 		RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_tcp_out) {
486 			total_len += LEN_IOC_FW3_STATE;
487 			if (total_len > sopt_size)
488 				goto nospace;
489 			ioc->src_addr.s_addr = ntohl(s->src_addr);
490 			ioc->dst_addr.s_addr = ntohl(s->dst_addr);
491 			ioc->src_port = ntohs(s->src_port);
492 			ioc->dst_port = ntohs(s->dst_port);
493 			ioc->cpu_id = cpu;
494 			ioc->rule_id = s->stub->rulenum;
495 			ioc->proto = IPPROTO_TCP;
496 			ioc->life = s->timestamp +
497 				sysctl_var_udp_timeout - time_uptime;
498 			ioc++;
499 		}
500 		RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_udp_in) {
501 			total_len += LEN_IOC_FW3_STATE;
502 			if (total_len > sopt_size)
503 				goto nospace;
504 			ioc->src_addr.s_addr = ntohl(s->src_addr);
505 			ioc->dst_addr.s_addr = ntohl(s->dst_addr);
506 			ioc->src_port = ntohs(s->src_port);
507 			ioc->dst_port = ntohs(s->dst_port);
508 			ioc->cpu_id = cpu;
509 			ioc->rule_id = s->stub->rulenum;
510 			ioc->proto = IPPROTO_UDP;
511 			ioc->life = s->timestamp +
512 				sysctl_var_udp_timeout - time_uptime;
513 			ioc++;
514 		}
515 		RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_udp_out) {
516 			total_len += LEN_IOC_FW3_STATE;
517 			if (total_len > sopt_size)
518 				goto nospace;
519 			ioc->src_addr.s_addr = ntohl(s->src_addr);
520 			ioc->dst_addr.s_addr = ntohl(s->dst_addr);
521 			ioc->src_port = ntohs(s->src_port);
522 			ioc->dst_port = ntohs(s->dst_port);
523 			ioc->cpu_id = cpu;
524 			ioc->rule_id = s->stub->rulenum;
525 			ioc->proto = IPPROTO_UDP;
526 			ioc->life = s->timestamp +
527 				sysctl_var_udp_timeout - time_uptime;
528 			ioc++;
529 		}
530 	}
531 
532 	sopt->sopt_valsize = total_len;
533 	return 0;
534 nospace:
535 	return 0;
536 }
537 
538 void
539 ip_fw3_state_cleanup_dispatch(netmsg_t nmsg)
540 {
541 
542 	struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
543 	struct ipfw3_state *s, *tmp;
544 
545 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_in, tmp) {
546 		if (time_uptime - s->timestamp > sysctl_var_icmp_timeout) {
547 			RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_in, s);
548 			kfree(s, M_IPFW3_STATE);
549 		}
550 	}
551 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_out, tmp) {
552 		if (time_uptime - s->timestamp > sysctl_var_icmp_timeout) {
553 			RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_out, s);
554 			kfree(s, M_IPFW3_STATE);
555 		}
556 	}
557 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_in, tmp) {
558 		if (time_uptime - s->timestamp > sysctl_var_tcp_timeout) {
559 			RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_in, s);
560 			kfree(s, M_IPFW3_STATE);
561 		}
562 	}
563 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_out, tmp) {
564 		if (time_uptime - s->timestamp > sysctl_var_tcp_timeout) {
565 			RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_out, s);
566 			kfree(s, M_IPFW3_STATE);
567 		}
568 	}
569 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_in, tmp) {
570 		if (time_uptime - s->timestamp > sysctl_var_udp_timeout) {
571 			RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_in, s);
572 			kfree(s, M_IPFW3_STATE);
573 		}
574 	}
575 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_out, tmp) {
576 		if (time_uptime - s->timestamp > sysctl_var_udp_timeout) {
577 			RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_out, s);
578 			kfree(s, M_IPFW3_STATE);
579 		}
580 	}
581 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
582 }
583 
584 void
585 ip_fw3_state_cleanup(void *dummy __unused)
586 {
587 	struct netmsg_base msg;
588 	netmsg_init(&msg, NULL, &curthread->td_msgport, 0,
589 			ip_fw3_state_cleanup_dispatch);
590 	netisr_domsg(&msg, 0);
591 
592 	callout_reset(&ip_fw3_state_cleanup_callout,
593 			sysctl_var_cleanup_interval * hz,
594 			ip_fw3_state_cleanup, NULL);
595 }
596 
597 int
598 ip_fw3_ctl_state_sockopt(struct sockopt *sopt)
599 {
600 	int error = 0;
601 	switch (sopt->sopt_name) {
602 		case IP_FW_STATE_ADD:
603 			error = ip_fw3_ctl_state_add(sopt);
604 			break;
605 		case IP_FW_STATE_DEL:
606 			error = ip_fw3_ctl_state_delete(sopt);
607 			break;
608 		case IP_FW_STATE_FLUSH:
609 			error = ip_fw3_ctl_state_flush(sopt);
610 			break;
611 		case IP_FW_STATE_GET:
612 			error = ip_fw3_ctl_state_get(sopt);
613 			break;
614 	}
615 	return error;
616 }
617 
618 void
619 ip_fw3_state_init_dispatch(netmsg_t msg)
620 {
621 	struct ipfw3_state_context *tmp;
622 
623 	tmp = kmalloc(LEN_STATE_CTX, M_IPFW3_STATE, M_WAITOK | M_ZERO);
624 	RB_INIT(&tmp->rb_icmp_in);
625 	RB_INIT(&tmp->rb_icmp_out);
626 	RB_INIT(&tmp->rb_tcp_in);
627 	RB_INIT(&tmp->rb_tcp_out);
628 	RB_INIT(&tmp->rb_udp_in);
629 	RB_INIT(&tmp->rb_udp_out);
630 	fw3_state_ctx[mycpuid] = tmp;
631 	netisr_forwardmsg_all(&msg->base, mycpuid + 1);
632 }
633 
634 void
635 ip_fw3_state_fini_dispatch(netmsg_t msg)
636 {
637 	struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
638 	struct ipfw3_state *s, *tmp;
639 
640 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_in, tmp) {
641 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_in, s);
642 		if (s != NULL) {
643 			kfree(s, M_IPFW3_STATE);
644 		}
645 	}
646 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_out, tmp) {
647 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_out, s);
648 		if (s != NULL) {
649 			kfree(s, M_IPFW3_STATE);
650 		}
651 	}
652 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_in, tmp) {
653 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_in, s);
654 		if (s != NULL) {
655 			kfree(s, M_IPFW3_STATE);
656 		}
657 	}
658 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_out, tmp) {
659 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_out, s);
660 		if (s != NULL) {
661 			kfree(s, M_IPFW3_STATE);
662 		}
663 	}
664 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_in, tmp) {
665 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_in, s);
666 		if (s != NULL) {
667 			kfree(s, M_IPFW3_STATE);
668 		}
669 	}
670 	RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_out, tmp) {
671 		RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_out, s);
672 		if (s != NULL) {
673 			kfree(s, M_IPFW3_STATE);
674 		}
675 	}
676 	kfree(fw3_state_ctx[mycpuid], M_IPFW3_STATE);
677 	fw3_state_ctx[mycpuid] = NULL;
678 	netisr_forwardmsg_all(&msg->base, mycpuid + 1);
679 }
680 
681 
682 void
683 ip_fw3_state_fini(void)
684 {
685 	struct netmsg_base msg;
686 
687 	netmsg_init(&msg, NULL, &curthread->td_msgport,
688 		0, ip_fw3_state_fini_dispatch);
689 
690 	netisr_domsg(&msg, 0);
691 	callout_stop(&ip_fw3_state_cleanup_callout);
692 }
693 
694 void
695 ip_fw3_state_init(void)
696 {
697 	struct netmsg_base msg;
698 
699 	ip_fw3_ctl_state_ptr = ip_fw3_ctl_state_sockopt;
700 	callout_init_mp(&ip_fw3_state_cleanup_callout);
701 	callout_reset(&ip_fw3_state_cleanup_callout,
702 			sysctl_var_cleanup_interval * hz,
703 			ip_fw3_state_cleanup,
704 			NULL);
705 	netmsg_init(&msg, NULL, &curthread->td_msgport,
706 			0, ip_fw3_state_init_dispatch);
707 	netisr_domsg(&msg, 0);
708 }
709 
710 
711 void
712 ip_fw3_state_modevent(int type)
713 {
714 	switch (type) {
715 		case MOD_LOAD:
716 			ip_fw3_state_init();
717 			break;
718 		case MOD_UNLOAD:
719 			ip_fw3_state_fini();
720 			break;
721 	}
722 }
723 
724