1 /*
2  * Copyright (c) 2014 - 2016 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/syslog.h>
42 #include <sys/systimer.h>
43 #include <sys/thread2.h>
44 #include <sys/in_cksum.h>
45 
46 #include <net/if.h>
47 #include <net/ethernet.h>
48 #include <net/netmsg2.h>
49 #include <net/netisr2.h>
50 #include <net/route.h>
51 
52 #include <netinet/ip.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/in_var.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/ip_var.h>
58 #include <netinet/ip_icmp.h>
59 #include <netinet/tcp.h>
60 #include <netinet/tcp_timer.h>
61 #include <netinet/tcp_var.h>
62 #include <netinet/tcpip.h>
63 #include <netinet/udp.h>
64 #include <netinet/udp_var.h>
65 #include <netinet/ip_divert.h>
66 #include <netinet/if_ether.h>
67 
68 #include <net/ipfw3/ip_fw.h>
69 #include <net/ipfw3/ip_fw3_table.h>
70 #include <net/ipfw3/ip_fw3_sync.h>
71 
72 #include "ip_fw3_basic.h"
73 
74 #define TIME_LEQ(a, b)	((int)((a) - (b)) <= 0)
75 
76 extern struct ipfw_context	*ipfw_ctx[MAXCPU];
77 extern int fw_verbose;
78 extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt;
79 extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt;
80 extern ipfw_sync_send_state_t *ipfw_sync_send_state_prt;
81 extern ipfw_sync_install_state_t *ipfw_sync_install_state_prt;
82 
83 static int ip_fw_basic_loaded;
84 static struct netmsg_base ipfw_timeout_netmsg;	/* schedule ipfw timeout */
85 static struct callout ipfw_tick_callout;
86 static int state_lifetime = 20;
87 static int state_expiry_check_interval = 10;
88 static int state_count_max = 4096;
89 static int state_hash_size_old = 0;
90 static int state_hash_size = 4096;
91 
92 
93 static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS);
94 void adjust_hash_size_dispatch(netmsg_t nmsg);
95 
96 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic,
97 		CTLFLAG_RW, 0, "Firewall Basic");
98 SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size,
99 		CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0,
100 		ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size");
101 
102 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW,
103 		&state_lifetime, 0, "default life time");
104 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO,
105 		state_expiry_check_interval, CTLFLAG_RW,
106 		&state_expiry_check_interval, 0,
107 		"default state expiry check interval");
108 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW,
109 		&state_count_max, 0, "maximum of state");
110 
111 static int
112 ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS)
113 {
114 	int error, value = 0;
115 
116 	state_hash_size_old = state_hash_size;
117 	value = state_hash_size;
118 	error = sysctl_handle_int(oidp, &value, 0, req);
119 	if (error || !req->newptr) {
120 		goto back;
121 	}
122 	/*
123 	 * Make sure we have a power of 2 and
124 	 * do not allow more than 64k entries.
125 	 */
126 	error = EINVAL;
127 	if (value <= 1 || value > 65536) {
128 		goto back;
129 	}
130 	if ((value & (value - 1)) != 0) {
131 		goto back;
132 	}
133 
134 	error = 0;
135 	if (state_hash_size != value) {
136 		state_hash_size = value;
137 
138 		struct netmsg_base *msg, the_msg;
139 		msg = &the_msg;
140 		bzero(msg,sizeof(struct netmsg_base));
141 
142 		netmsg_init(msg, NULL, &curthread->td_msgport,
143 				0, adjust_hash_size_dispatch);
144 		ifnet_domsg(&msg->lmsg, 0);
145 	}
146 back:
147 	return error;
148 }
149 
150 void
151 adjust_hash_size_dispatch(netmsg_t nmsg)
152 {
153 	struct ipfw_state_context *state_ctx;
154 	struct ip_fw_state *the_state, *state;
155 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
156 	int i;
157 
158 	for (i = 0; i < state_hash_size_old; i++) {
159 		state_ctx = &ctx->state_ctx[i];
160 		if (state_ctx != NULL) {
161 			state = state_ctx->state;
162 			while (state != NULL) {
163 				the_state = state;
164 				state = state->next;
165 				kfree(the_state, M_IPFW3_BASIC);
166 				the_state = NULL;
167 			}
168 		}
169 	}
170 	kfree(ctx->state_ctx,M_IPFW3_BASIC);
171 	ctx->state_ctx = kmalloc(state_hash_size *
172 				sizeof(struct ipfw_state_context),
173 				M_IPFW3_BASIC, M_WAITOK | M_ZERO);
174 	ctx->state_hash_size = state_hash_size;
175 	ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
176 }
177 
178 
179 /*	prototype of the checker functions	*/
180 void check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
181 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
182 void check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
183 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
184 void check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
185 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
186 void check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
187 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
188 
189 void check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
190 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
191 void check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
192 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
193 void check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
194 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
195 void check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
196 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
197 void check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
198 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
199 void check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
200 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
201 void check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
202 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
203 void check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
204 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
205 void check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
206 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
207 void check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
208 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
209 void check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
210 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
211 void check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
212 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
213 void check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
214 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
215 void check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
216 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
217 void check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
218 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
219 void check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
220 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
221 void check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
222 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
223 void check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
224 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
225 void check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
226 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
227 void check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
228 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
229 void check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
230 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
231 
232 /*	prototype of the utility functions	*/
233 int match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid,
234 	struct ip_fw_state *state);
235 int count_match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid,
236 	struct ip_fw_state *state, int *count);
237 
238 static struct ip_fw *lookup_next_rule(struct ip_fw *me);
239 static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd);
240 static __inline int hash_packet(struct ipfw_flow_id *id);
241 
242 static __inline int
243 hash_packet(struct ipfw_flow_id *id)
244 {
245 	uint32_t i;
246 	i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^
247 		(id->dst_port) ^ (id->src_port);
248 	i &= state_hash_size - 1;
249 	return i;
250 }
251 
252 static struct ip_fw *
253 lookup_next_rule(struct ip_fw *me)
254 {
255 	struct ip_fw *rule = NULL;
256 	ipfw_insn *cmd;
257 
258 	/* look for action, in case it is a skipto */
259 	cmd = ACTION_PTR(me);
260 	if ((int)cmd->module == MODULE_BASIC_ID &&
261 		(int)cmd->opcode == O_BASIC_SKIPTO) {
262 		for (rule = me->next; rule; rule = rule->next) {
263 			if (rule->rulenum >= cmd->arg1)
264 				break;
265 		}
266 	}
267 	if (rule == NULL) /* failure or not a skipto */
268 		rule = me->next;
269 
270 	me->next_rule = rule;
271 	return rule;
272 }
273 
274 /*
275  * return value
276  * 0 : not match  1: same direction 2: reverse direction
277  */
278 int
279 match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid, struct ip_fw_state *state)
280 {
281 	 if (fid->src_ip == state->flow_id.src_ip &&
282 		 fid->dst_ip == state->flow_id.dst_ip &&
283 		 (fid->src_port == state->flow_id.src_port ||
284 				 state->flow_id.src_port == 0) &&
285 		 (fid->dst_port == state->flow_id.dst_port ||
286 				 state->flow_id.dst_port == 0)) {
287 		 return 1;
288 	 }
289 	 if (fid->src_ip == state->flow_id.dst_ip &&
290 		 fid->dst_ip == state->flow_id.src_ip &&
291 		 (fid->src_port == state->flow_id.dst_port ||
292 				 state->flow_id.dst_port == 0) &&
293 		 (fid->dst_port == state->flow_id.src_port ||
294 				 state->flow_id.src_port == 0)) {
295 		 return 2;
296 	 }
297 	 return 0;
298 }
299 
300 /*
301  * return 1 when more states than limit
302  * arg3: limit type (1=src ip, 2=src port, 3=dst ip, 4=dst port)
303  * arg1: limit
304  */
305 int
306 count_match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid,
307 	struct ip_fw_state *state, int *count)
308 {
309 	 if ((cmd->arg3 == 1 && fid->src_ip == state->flow_id.src_ip) ||
310 		 (cmd->arg3 == 2 && fid->src_port == state->flow_id.src_port) ||
311 		 (cmd->arg3 == 3 && fid->dst_ip == state->flow_id.dst_ip) ||
312 		 (cmd->arg3 == 4 && fid->dst_port == state->flow_id.dst_port)) {
313 		 *count = *count + 1;
314 		 if (*count >= cmd->arg1)
315 			 return 1;
316 	 }
317 	  return 0;
318 }
319 
320 /*
321  * when all = 1, it will check all the state_ctx
322  * all = 1 during keep-state
323  * all = 0 during check-state
324  *
325  * in the cmd of keep_state
326  * arg3=type arg1=limit
327  */
328 static struct ip_fw_state *
329 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all)
330 {
331 	struct ip_fw_state *state = NULL;
332 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
333 	struct ipfw_state_context *state_ctx;
334 	int start, end, i, count = 0;
335 
336 	if (all && cmd->arg1) {
337 		start = 0;
338 		end = state_hash_size - 1;
339 	} else {
340 		start = hash_packet(&args->f_id);
341 		end = hash_packet(&args->f_id);
342 	}
343 
344 	for (i = start; i <= end; i++) {
345 		state_ctx = &ctx->state_ctx[i];
346 		if (state_ctx != NULL) {
347 			state = state_ctx->state;
348 			struct ipfw_flow_id	*fid = &args->f_id;
349 			while (state != NULL) {
350 				/* has limit and already exceed the limit */
351 				if (cmd->arg1 &&
352 					count_match_state(cmd, fid,
353 							state, &count) != 0) {
354 					*limited = 1;
355 					 goto done;
356 				 }
357 
358 				if (fid->proto == state->flow_id.proto &&
359 						 match_state(cmd, fid, state) != 0)
360 					 goto done;
361 
362 				state = state->next;
363 			}
364 		}
365 	}
366 done:
367 	return state;
368 }
369 
370 static struct ip_fw_state *
371 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args)
372 {
373 	struct ip_fw_state *state;
374 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
375 	struct ipfw_state_context *state_ctx;
376 	int hash = hash_packet(&args->f_id);
377 	state_ctx = &ctx->state_ctx[hash];
378 	state = kmalloc(sizeof(struct ip_fw_state),
379 			M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
380 	if (state == NULL) {
381 		return NULL;
382 	}
383 	state->stub = rule;
384 	state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ;
385 	state->timestamp = time_second;
386 	state->expiry = 0;
387 	bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id));
388 	//append the state into the state chian
389 	if (state_ctx->last != NULL)
390 		state_ctx->last->next = state;
391 	else
392 		state_ctx->state = state;
393 	state_ctx->last = state;
394 	state_ctx->count++;
395 	ipfw_sync_send_state_prt(state, mycpuid, hash);
396 	return state;
397 }
398 
399 void
400 ipfw_sync_install_state(struct cmd_send_state *cmd)
401 {
402         struct ip_fw_state *state;
403         struct ipfw_context *ctx = ipfw_ctx[cmd->cpu];
404         struct ipfw_state_context *state_ctx;
405         struct ip_fw *rule;
406 
407         state_ctx = &ctx->state_ctx[cmd->hash];
408         state = kmalloc(sizeof(struct ip_fw_state),
409                         M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
410         if (state == NULL) {
411                 return;
412         }
413         for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
414                 if (rule->rulenum == cmd->rulenum) {
415                         goto found;
416                 }
417         }
418         return;
419 found:
420         state->stub = rule;
421         state->lifetime = cmd->lifetime;
422         state->timestamp = time_second;
423         state->expiry = 0;
424         bcopy(&cmd->flow, &state->flow_id, sizeof(struct ipfw_flow_id));
425         //append the state into the state chian
426         if (state_ctx->last != NULL)
427                 state_ctx->last->next = state;
428         else
429                 state_ctx->state = state;
430         state_ctx->last = state;
431         state_ctx->count++;
432 }
433 
434 static int
435 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
436 {
437 	if (ifp == NULL)	/* no iface with this packet, match fails */
438 		return 0;
439 
440 	/* Check by name or by IP address */
441 	if (cmd->name[0] != '\0') { /* match by name */
442 		/* Check name */
443 		if (cmd->p.glob) {
444 			if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
445 				return(1);
446 		} else {
447 			if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
448 				return(1);
449 		}
450 	} else {
451 		struct ifaddr_container *ifac;
452 
453 		TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
454 			struct ifaddr *ia = ifac->ifa;
455 
456 			if (ia->ifa_addr == NULL)
457 				continue;
458 			if (ia->ifa_addr->sa_family != AF_INET)
459 				continue;
460 			if (cmd->p.ip.s_addr ==
461 				((struct sockaddr_in *)
462 				(ia->ifa_addr))->sin_addr.s_addr)
463 					return(1);	/* match */
464 
465 		}
466 	}
467 	return 0;	/* no match, fail ... */
468 }
469 
470 /* implimentation of the checker functions */
471 void
472 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
473 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
474 {
475 	(*f)->pcnt++;
476 	(*f)->bcnt += ip_len;
477 	(*f)->timestamp = time_second;
478 	*cmd_ctl = IP_FW_CTL_NEXT;
479 }
480 
481 void
482 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
483 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
484 {
485 	(*f)->pcnt++;
486 	(*f)->bcnt += ip_len;
487 	(*f)->timestamp = time_second;
488 	if ((*f)->next_rule == NULL)
489 		lookup_next_rule(*f);
490 	*f = (*f)->next_rule;
491 	*cmd_ctl = IP_FW_CTL_AGAIN;
492 }
493 
494 void
495 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
496 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
497 {
498 	struct sockaddr_in *sin, *sa;
499 	struct m_tag *mtag;
500 
501 	if ((*args)->eh) {	/* not valid on layer2 pkts */
502 		*cmd_ctl=IP_FW_CTL_NEXT;
503 		return;
504 	}
505 
506 	(*f)->pcnt++;
507 	(*f)->bcnt += ip_len;
508 	(*f)->timestamp = time_second;
509 	if ((*f)->next_rule == NULL)
510 		lookup_next_rule(*f);
511 
512 	mtag = m_tag_get(PACKET_TAG_IPFORWARD,
513 			sizeof(*sin), M_NOWAIT);
514 	if (mtag == NULL) {
515 		*cmd_val = IP_FW_DENY;
516 		*cmd_ctl = IP_FW_CTL_DONE;
517 		return;
518 	}
519 	sin = m_tag_data(mtag);
520 	sa = &((ipfw_insn_sa *)cmd)->sa;
521 	/* arg3: count of the dest, arg1: type of fwd */
522 	int i = 0;
523 	if(cmd->arg3 > 1) {
524 		if (cmd->arg1 == 0) {		/* type: random */
525 			i = krandom() % cmd->arg3;
526 		} else if (cmd->arg1 == 1) {	/* type: round-robin */
527 			i = cmd->arg2++ % cmd->arg3;
528 		} else if (cmd->arg1 == 2) {	/* type: sticky */
529 			struct ip *ip = mtod((*args)->m, struct ip *);
530 			i = ip->ip_src.s_addr & (cmd->arg3 - 1);
531 		}
532 		sa += i;
533 	}
534 	*sin = *sa;	/* apply the destination */
535 	m_tag_prepend((*args)->m, mtag);
536 	(*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED;
537 	(*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
538 	*cmd_ctl = IP_FW_CTL_DONE;
539 	*cmd_val = IP_FW_PASS;
540 }
541 
542 void
543 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
544 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
545 {
546 	struct ip_fw_state *state=NULL;
547 	int limited = 0 ;
548 	state = lookup_state(*args, cmd, &limited, 0);
549 	if (state != NULL) {
550 		state->pcnt++;
551 		state->bcnt += ip_len;
552 		state->timestamp = time_second;
553 		(*f)->pcnt++;
554 		(*f)->bcnt += ip_len;
555 		(*f)->timestamp = time_second;
556 		*f = state->stub;
557 		*cmd_ctl = IP_FW_CTL_CHK_STATE;
558 	} else {
559 		*cmd_ctl = IP_FW_CTL_NEXT;
560 	}
561 }
562 
563 void
564 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
565 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
566 {
567 	*cmd_ctl = IP_FW_CTL_NO;
568 	*cmd_val = ((*args)->oif == NULL);
569 }
570 
571 void
572 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
573 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
574 {
575 	*cmd_ctl = IP_FW_CTL_NO;
576 	*cmd_val = ((*args)->oif != NULL);
577 }
578 
579 void
580 check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
581 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
582 {
583 	*cmd_ctl = IP_FW_CTL_NO;
584 	*cmd_val = iface_match((*args)->oif ?
585 			(*args)->oif : (*args)->m->m_pkthdr.rcvif,
586 			(ipfw_insn_if *)cmd);
587 }
588 
589 void
590 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
591 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
592 {
593 	*cmd_ctl = IP_FW_CTL_NO;
594 	*cmd_val = ((*args)->f_id.proto == cmd->arg1);
595 }
596 
597 void
598 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
599 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
600 {
601 	*cmd_ctl = IP_FW_CTL_NO;
602 	*cmd_val = (krandom() % 100) < cmd->arg1;
603 }
604 
605 void
606 check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
607 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
608 {
609 	struct in_addr src_ip;
610 	u_int hlen = 0;
611 	struct mbuf *m = (*args)->m;
612 	struct ip *ip = mtod(m, struct ip *);
613 	src_ip = ip->ip_src;
614 	if ((*args)->eh == NULL ||
615 		(m->m_pkthdr.len >= sizeof(struct ip) &&
616 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
617 		hlen = ip->ip_hl << 2;
618 	}
619 	*cmd_val = (hlen > 0 &&
620 			((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
621 	*cmd_ctl = IP_FW_CTL_NO;
622 }
623 
624 void
625 check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
626 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
627 {
628 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
629 	struct ipfw_table_context *table_ctx;
630 	struct radix_node_head *rnh;
631 	struct sockaddr_in sa;
632 
633 	struct mbuf *m = (*args)->m;
634 	struct ip *ip = mtod(m, struct ip *);
635 	struct in_addr src_ip = ip->ip_src;
636 
637 	*cmd_val = IP_FW_NOT_MATCH;
638 
639 	table_ctx = ctx->table_ctx;
640 	table_ctx += cmd->arg1;
641 
642         if (table_ctx->type != 0) {
643                 rnh = table_ctx->node;
644                 sa.sin_len = 8;
645                 sa.sin_addr.s_addr = src_ip.s_addr;
646                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
647                         *cmd_val = IP_FW_MATCH;
648         }
649 	*cmd_ctl = IP_FW_CTL_NO;
650 }
651 
652 void
653 check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
654 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
655 {
656 	struct in_addr src_ip;
657 	u_int hlen = 0;
658 	struct mbuf *m = (*args)->m;
659 	struct ip *ip = mtod(m, struct ip *);
660 	src_ip = ip->ip_src;
661 	if ((*args)->eh == NULL ||
662 		(m->m_pkthdr.len >= sizeof(struct ip) &&
663 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
664 		hlen = ip->ip_hl << 2;
665 	}
666 	*cmd_ctl = IP_FW_CTL_NO;
667 	if (hlen > 0) {
668 		struct ifnet *tif;
669 		tif = INADDR_TO_IFP(&src_ip);
670 		*cmd_val = (tif != NULL);
671 	} else {
672 		*cmd_val = IP_FW_NOT_MATCH;
673 	}
674 }
675 
676 void
677 check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
678 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
679 {
680 	struct in_addr src_ip;
681 	u_int hlen = 0;
682 	struct mbuf *m = (*args)->m;
683 	struct ip *ip = mtod(m, struct ip *);
684 	src_ip = ip->ip_src;
685 	if ((*args)->eh == NULL ||
686 		(m->m_pkthdr.len >= sizeof(struct ip) &&
687 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
688 		hlen = ip->ip_hl << 2;
689 	}
690 
691 	*cmd_ctl = IP_FW_CTL_NO;
692 	*cmd_val = (hlen > 0 &&
693 			((ipfw_insn_ip *)cmd)->addr.s_addr ==
694 			(src_ip.s_addr &
695 			((ipfw_insn_ip *)cmd)->mask.s_addr));
696 }
697 
698 void
699 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
700 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
701 {
702 	struct in_addr dst_ip;
703 	u_int hlen = 0;
704 	struct mbuf *m = (*args)->m;
705 	struct ip *ip = mtod(m, struct ip *);
706 	dst_ip = ip->ip_dst;
707 	if ((*args)->eh == NULL ||
708 		(m->m_pkthdr.len >= sizeof(struct ip) &&
709 		 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
710 		hlen = ip->ip_hl << 2;
711 	}
712 	*cmd_val = (hlen > 0 &&
713 			((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
714 	*cmd_ctl = IP_FW_CTL_NO;
715 }
716 
717 void
718 check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
719 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
720 {
721 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
722 	struct ipfw_table_context *table_ctx;
723 	struct radix_node_head *rnh;
724 	struct sockaddr_in sa;
725 
726 	struct mbuf *m = (*args)->m;
727 	struct ip *ip = mtod(m, struct ip *);
728 	struct in_addr dst_ip = ip->ip_dst;
729 
730 	*cmd_val = IP_FW_NOT_MATCH;
731 
732 	table_ctx = ctx->table_ctx;
733 	table_ctx += cmd->arg1;
734 
735         if (table_ctx->type != 0) {
736                 rnh = table_ctx->node;
737                 sa.sin_len = 8;
738                 sa.sin_addr.s_addr = dst_ip.s_addr;
739                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
740                         *cmd_val = IP_FW_MATCH;
741         }
742 	*cmd_ctl = IP_FW_CTL_NO;
743 }
744 
745 void
746 check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
747 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
748 {
749 	struct in_addr dst_ip;
750 	u_int hlen = 0;
751 	struct mbuf *m = (*args)->m;
752 	struct ip *ip = mtod(m, struct ip *);
753 	dst_ip = ip->ip_src;
754 	if ((*args)->eh == NULL ||
755 		(m->m_pkthdr.len >= sizeof(struct ip) &&
756 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
757 		hlen = ip->ip_hl << 2;
758 	}
759 	*cmd_ctl = IP_FW_CTL_NO;
760 	if (hlen > 0) {
761 		struct ifnet *tif;
762 		tif = INADDR_TO_IFP(&dst_ip);
763 		*cmd_val = (tif != NULL);
764 	} else {
765 		*cmd_val = IP_FW_NOT_MATCH;
766 	}
767 }
768 
769 void
770 check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
771 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
772 {
773 	struct in_addr dst_ip;
774 	u_int hlen = 0;
775 	struct mbuf *m = (*args)->m;
776 	struct ip *ip = mtod(m, struct ip *);
777 	dst_ip = ip->ip_src;
778 	if ((*args)->eh == NULL ||
779 		(m->m_pkthdr.len >= sizeof(struct ip) &&
780 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
781 		hlen = ip->ip_hl << 2;
782 	}
783 
784 	*cmd_ctl = IP_FW_CTL_NO;
785 	*cmd_val = (hlen > 0 &&
786 			((ipfw_insn_ip *)cmd)->addr.s_addr ==
787 			(dst_ip.s_addr &
788 			((ipfw_insn_ip *)cmd)->mask.s_addr));
789 }
790 
791 void
792 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
793 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
794 {
795 	struct ip_fw_state *state;
796 	int limited = 0;
797 
798 	*cmd_ctl = IP_FW_CTL_NO;
799 	state = lookup_state(*args, cmd, &limited, 1);
800 	if (limited == 1) {
801 		*cmd_val = IP_FW_NOT_MATCH;
802 	} else {
803 		if (state == NULL)
804 			state = install_state(*f, cmd, *args);
805 
806 		if (state != NULL) {
807 			state->pcnt++;
808 			state->bcnt += ip_len;
809 			state->timestamp = time_second;
810 			*cmd_val = IP_FW_MATCH;
811 		} else {
812 			*cmd_val = IP_FW_NOT_MATCH;
813 		}
814 	}
815 }
816 
817 void
818 check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
819 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
820 {
821 	struct m_tag *mtag = m_tag_locate((*args)->m,
822 			MTAG_IPFW, cmd->arg1, NULL);
823 	if (mtag == NULL) {
824 		mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT);
825 		if (mtag != NULL)
826 			m_tag_prepend((*args)->m, mtag);
827 
828 	}
829 	(*f)->pcnt++;
830 	(*f)->bcnt += ip_len;
831 	(*f)->timestamp = time_second;
832 	*cmd_ctl = IP_FW_CTL_NEXT;
833 }
834 
835 void
836 check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
837 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
838 {
839 	struct m_tag *mtag = m_tag_locate((*args)->m,
840 			MTAG_IPFW, cmd->arg1, NULL);
841 	if (mtag != NULL)
842 		m_tag_delete((*args)->m, mtag);
843 
844 	(*f)->pcnt++;
845 	(*f)->bcnt += ip_len;
846 	(*f)->timestamp = time_second;
847 	*cmd_ctl = IP_FW_CTL_NEXT;
848 }
849 
850 void
851 check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
852 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
853 {
854 	*cmd_ctl = IP_FW_CTL_NO;
855 	if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL )
856 		*cmd_val = IP_FW_MATCH;
857 	else
858 		*cmd_val = IP_FW_NOT_MATCH;
859 }
860 
861 void
862 check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
863         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
864 {
865         *cmd_ctl = IP_FW_CTL_NO;
866         if ((*args)->f_id.src_port == cmd->arg1)
867                 *cmd_val = IP_FW_MATCH;
868         else
869                 *cmd_val = IP_FW_NOT_MATCH;
870 }
871 
872 void
873 check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
874         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
875 {
876         *cmd_ctl = IP_FW_CTL_NO;
877         if ((*args)->f_id.dst_port == cmd->arg1)
878                 *cmd_val = IP_FW_MATCH;
879         else
880                 *cmd_val = IP_FW_NOT_MATCH;
881 }
882 
883 void
884 check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
885 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
886 {
887 	struct in_addr src_ip;
888 	u_int hlen = 0;
889 	struct mbuf *m = (*args)->m;
890 	struct ip *ip = mtod(m, struct ip *);
891 	src_ip = ip->ip_src;
892 	if ((*args)->eh == NULL ||
893 		(m->m_pkthdr.len >= sizeof(struct ip) &&
894 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
895 		hlen = ip->ip_hl << 2;
896 	}
897 	*cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
898 	*cmd_ctl = IP_FW_CTL_NO;
899 	if (*cmd_val && (*args)->f_id.src_port == cmd->arg1)
900 		*cmd_val = IP_FW_MATCH;
901 	else
902 		*cmd_val = IP_FW_NOT_MATCH;
903 }
904 
905 void
906 check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
907 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
908 {
909 	struct in_addr dst_ip;
910 	u_int hlen = 0;
911 	struct mbuf *m = (*args)->m;
912 	struct ip *ip = mtod(m, struct ip *);
913 	dst_ip = ip->ip_dst;
914 	if ((*args)->eh == NULL ||
915 		(m->m_pkthdr.len >= sizeof(struct ip) &&
916 		 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
917 		hlen = ip->ip_hl << 2;
918 	}
919 	*cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
920 	*cmd_ctl = IP_FW_CTL_NO;
921 	if (*cmd_val && (*args)->f_id.dst_port == cmd->arg1)
922 		*cmd_val = IP_FW_MATCH;
923 	else
924 		*cmd_val = IP_FW_NOT_MATCH;
925 }
926 
927 
928 
929 static void
930 ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state)
931 {
932 	struct ip_fw_state *state;
933 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
934 	struct ipfw_state_context *state_ctx;
935 	state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))];
936 	state = kmalloc(sizeof(struct ip_fw_state),
937 			M_IPFW3_BASIC, M_WAITOK | M_ZERO);
938 	struct ip_fw *rule = ctx->ipfw_rule_chain;
939 	while (rule != NULL) {
940 		if (rule->rulenum == ioc_state->rulenum) {
941 			break;
942 		}
943 		rule = rule->next;
944 	}
945 	if (rule == NULL)
946 		return;
947 
948 	state->stub = rule;
949 
950 	state->lifetime = ioc_state->lifetime == 0 ?
951 		state_lifetime : ioc_state->lifetime ;
952 	state->timestamp = time_second;
953 	state->expiry = ioc_state->expiry;
954 	bcopy(&ioc_state->flow_id, &state->flow_id,
955 			sizeof(struct ipfw_flow_id));
956 	//append the state into the state chian
957 	if (state_ctx->last != NULL)
958 		state_ctx->last->next = state;
959 	else
960 		state_ctx->state = state;
961 
962 	state_ctx->last = state;
963 	state_ctx->count++;
964 }
965 
966 /*
967  * if rule is NULL
968  * 		flush all states
969  * else
970  * 		flush states which stub is the rule
971  */
972 static void
973 ipfw_basic_flush_state(struct ip_fw *rule)
974 {
975 	struct ipfw_state_context *state_ctx;
976 	struct ip_fw_state *state,*the_state, *prev_state;
977 	struct ipfw_context *ctx;
978 	int i;
979 
980 	ctx = ipfw_ctx[mycpuid];
981 	for (i = 0; i < state_hash_size; i++) {
982 		state_ctx = &ctx->state_ctx[i];
983 		if (state_ctx != NULL) {
984 			state = state_ctx->state;
985 			prev_state = NULL;
986 			while (state != NULL) {
987 				if (rule != NULL && state->stub != rule) {
988 					prev_state = state;
989 					state = state->next;
990 				} else {
991 					if (prev_state == NULL)
992 						state_ctx->state = state->next;
993 					else
994 						prev_state->next = state->next;
995 
996 					the_state = state;
997 					state = state->next;
998 					kfree(the_state, M_IPFW3_BASIC);
999 					state_ctx->count--;
1000 					if (state == NULL)
1001 						state_ctx->last = prev_state;
1002 
1003 				}
1004 			}
1005 		}
1006 	}
1007 }
1008 
1009 /*
1010  * clean up expired state in every tick
1011  */
1012 static void
1013 ipfw_cleanup_expired_state(netmsg_t nmsg)
1014 {
1015 	struct ip_fw_state *state,*the_state,*prev_state;
1016 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
1017 	struct ipfw_state_context *state_ctx;
1018 	int i;
1019 
1020 	for (i = 0; i < state_hash_size; i++) {
1021 		prev_state = NULL;
1022 		state_ctx = &(ctx->state_ctx[i]);
1023 		if (ctx->state_ctx != NULL) {
1024 			state = state_ctx->state;
1025 			while (state != NULL) {
1026 				if (IS_EXPIRED(state)) {
1027 					if (prev_state == NULL)
1028 						state_ctx->state = state->next;
1029 					else
1030 						prev_state->next = state->next;
1031 
1032 					the_state =state;
1033 					state = state->next;
1034 
1035 					if (the_state == state_ctx->last)
1036 						state_ctx->last = NULL;
1037 
1038 
1039 					kfree(the_state, M_IPFW3_BASIC);
1040 					state_ctx->count--;
1041 				} else {
1042 					prev_state = state;
1043 					state = state->next;
1044 				}
1045 			}
1046 		}
1047 	}
1048 	ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
1049 }
1050 
1051 static void
1052 ipfw_tick(void *dummy __unused)
1053 {
1054 	struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg;
1055 	KKASSERT(mycpuid == IPFW_CFGCPUID);
1056 
1057 	crit_enter();
1058 	KKASSERT(lmsg->ms_flags & MSGF_DONE);
1059 	if (IPFW_BASIC_LOADED) {
1060 		lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg);
1061 		/* ipfw_timeout_netmsg's handler reset this callout */
1062 	}
1063 	crit_exit();
1064 
1065 	struct netmsg_base *msg;
1066 	struct netmsg_base the_msg;
1067 	msg = &the_msg;
1068 	bzero(msg,sizeof(struct netmsg_base));
1069 
1070 	netmsg_init(msg, NULL, &curthread->td_msgport, 0,
1071 			ipfw_cleanup_expired_state);
1072 	ifnet_domsg(&msg->lmsg, 0);
1073 }
1074 
1075 static void
1076 ipfw_tick_dispatch(netmsg_t nmsg)
1077 {
1078 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1079 	KKASSERT(IPFW_BASIC_LOADED);
1080 
1081 	/* Reply ASAP */
1082 	crit_enter();
1083 	lwkt_replymsg(&nmsg->lmsg, 0);
1084 	crit_exit();
1085 
1086 	callout_reset(&ipfw_tick_callout,
1087 			state_expiry_check_interval * hz, ipfw_tick, NULL);
1088 }
1089 
1090 static void
1091 ipfw_basic_init_dispatch(netmsg_t nmsg)
1092 {
1093 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1094 	KKASSERT(IPFW3_LOADED);
1095 
1096 	int error = 0;
1097 	callout_init_mp(&ipfw_tick_callout);
1098 	netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport,
1099 			MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch);
1100 	callout_reset(&ipfw_tick_callout,
1101 			state_expiry_check_interval * hz, ipfw_tick, NULL);
1102 	lwkt_replymsg(&nmsg->lmsg, error);
1103 	ip_fw_basic_loaded=1;
1104 }
1105 
1106 static int
1107 ipfw_basic_init(void)
1108 {
1109 	ipfw_basic_flush_state_prt = ipfw_basic_flush_state;
1110 	ipfw_basic_append_state_prt = ipfw_basic_add_state;
1111 	ipfw_sync_install_state_prt = ipfw_sync_install_state;
1112 
1113 	register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME);
1114 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT,
1115 			(filter_func)check_count);
1116 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO,
1117 			(filter_func)check_skipto);
1118 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD,
1119 			(filter_func)check_forward);
1120 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
1121 			(filter_func)check_keep_state);
1122 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
1123 			(filter_func)check_check_state);
1124 
1125 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1126 			O_BASIC_IN, (filter_func)check_in);
1127 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1128 			O_BASIC_OUT, (filter_func)check_out);
1129 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1130 			O_BASIC_VIA, (filter_func)check_via);
1131 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1132 			O_BASIC_XMIT, (filter_func)check_via);
1133 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1134 			O_BASIC_RECV, (filter_func)check_via);
1135 
1136 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1137 			O_BASIC_PROTO, (filter_func)check_proto);
1138 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1139 			O_BASIC_PROB, (filter_func)check_prob);
1140 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1141 			O_BASIC_IP_SRC, (filter_func)check_from);
1142 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1143 			O_BASIC_IP_SRC_LOOKUP, (filter_func)check_from_lookup);
1144 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1145 			O_BASIC_IP_SRC_ME, (filter_func)check_from_me);
1146 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1147 			O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask);
1148 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1149 			O_BASIC_IP_DST, (filter_func)check_to);
1150 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1151 			O_BASIC_IP_DST_LOOKUP, (filter_func)check_to_lookup);
1152 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1153 			O_BASIC_IP_DST_ME, (filter_func)check_to_me);
1154 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1155 			O_BASIC_IP_DST_MASK, (filter_func)check_to_mask);
1156 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1157 			O_BASIC_TAG, (filter_func)check_tag);
1158 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1159 			O_BASIC_UNTAG, (filter_func)check_untag);
1160 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1161 			O_BASIC_TAGGED, (filter_func)check_tagged);
1162 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1163 			O_BASIC_IP_SRCPORT, (filter_func)check_src_port);
1164 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1165 			O_BASIC_IP_DSTPORT, (filter_func)check_dst_port);
1166 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1167 			O_BASIC_IP_SRC_N_PORT, (filter_func)check_src_n_port);
1168 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1169 			O_BASIC_IP_DST_N_PORT, (filter_func)check_dst_n_port);
1170 
1171 	int cpu;
1172 	struct ipfw_context *ctx;
1173 
1174 	for (cpu = 0; cpu < ncpus; cpu++) {
1175 		ctx = ipfw_ctx[cpu];
1176 		if (ctx != NULL) {
1177 			ctx->state_ctx = kmalloc(state_hash_size *
1178 					sizeof(struct ipfw_state_context),
1179 					M_IPFW3_BASIC, M_WAITOK | M_ZERO);
1180 			ctx->state_hash_size = state_hash_size;
1181 		}
1182 	}
1183 
1184 	struct netmsg_base smsg;
1185 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
1186 			0, ipfw_basic_init_dispatch);
1187 	lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1188 	return 0;
1189 }
1190 
1191 static void
1192 ipfw_basic_stop_dispatch(netmsg_t nmsg)
1193 {
1194 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1195 	KKASSERT(IPFW3_LOADED);
1196 	int error = 0;
1197 	callout_stop(&ipfw_tick_callout);
1198 	netmsg_service_sync();
1199 	crit_enter();
1200 	lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg);
1201 	crit_exit();
1202 	lwkt_replymsg(&nmsg->lmsg, error);
1203 	ip_fw_basic_loaded=0;
1204 }
1205 
1206 static int
1207 ipfw_basic_stop(void)
1208 {
1209 	int cpu,i;
1210 	struct ipfw_state_context *state_ctx;
1211 	struct ip_fw_state *state,*the_state;
1212 	struct ipfw_context *ctx;
1213 	if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) {
1214 		ipfw_basic_flush_state_prt = NULL;
1215 		ipfw_basic_append_state_prt = NULL;
1216 
1217 		for (cpu = 0; cpu < ncpus; cpu++) {
1218 			ctx = ipfw_ctx[cpu];
1219 			if (ctx != NULL) {
1220 				for (i = 0; i < state_hash_size; i++) {
1221 					state_ctx = &ctx->state_ctx[i];
1222 					if (state_ctx != NULL) {
1223 						state = state_ctx->state;
1224 						while (state != NULL) {
1225 							the_state = state;
1226 							state = state->next;
1227 							if (the_state ==
1228 								state_ctx->last)
1229 							state_ctx->last = NULL;
1230 
1231 							kfree(the_state,
1232 								M_IPFW3_BASIC);
1233 						}
1234 					}
1235 				}
1236 				ctx->state_hash_size = 0;
1237 				kfree(ctx->state_ctx, M_IPFW3_BASIC);
1238 				ctx->state_ctx = NULL;
1239 			}
1240 		}
1241 		struct netmsg_base smsg;
1242 		netmsg_init(&smsg, NULL, &curthread->td_msgport,
1243 				0, ipfw_basic_stop_dispatch);
1244 		return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1245 	}
1246 	return 1;
1247 }
1248 
1249 
1250 static int
1251 ipfw3_basic_modevent(module_t mod, int type, void *data)
1252 {
1253 	int err;
1254 	switch (type) {
1255 		case MOD_LOAD:
1256 			err = ipfw_basic_init();
1257 			break;
1258 		case MOD_UNLOAD:
1259 			err = ipfw_basic_stop();
1260 			break;
1261 		default:
1262 			err = 1;
1263 	}
1264 	return err;
1265 }
1266 
1267 static moduledata_t ipfw3_basic_mod = {
1268 	"ipfw3_basic",
1269 	ipfw3_basic_modevent,
1270 	NULL
1271 };
1272 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
1273 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1);
1274 MODULE_VERSION(ipfw3_basic, 1);
1275