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