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