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