1 /*
2  * Copyright (c) 2014 - 2017 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 struct ipfw_sync_context sync_ctx;
78 extern int fw_verbose;
79 extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt;
80 extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt;
81 extern ipfw_sync_send_state_t *ipfw_sync_send_state_prt;
82 extern ipfw_sync_install_state_t *ipfw_sync_install_state_prt;
83 
84 static int ip_fw_basic_loaded;
85 static struct netmsg_base ipfw_timeout_netmsg;	/* schedule ipfw timeout */
86 static struct callout ipfw_tick_callout;
87 static int state_lifetime = 20;
88 static int state_expiry_check_interval = 10;
89 static int state_count_max = 4096;
90 static int state_hash_size_old = 0;
91 static int state_hash_size = 4096;
92 
93 
94 static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS);
95 void adjust_hash_size_dispatch(netmsg_t nmsg);
96 
97 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic,
98 		CTLFLAG_RW, 0, "Firewall Basic");
99 SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size,
100 		CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0,
101 		ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size");
102 
103 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW,
104 		&state_lifetime, 0, "default life time");
105 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO,
106 		state_expiry_check_interval, CTLFLAG_RW,
107 		&state_expiry_check_interval, 0,
108 		"default state expiry check interval");
109 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW,
110 		&state_count_max, 0, "maximum of state");
111 
112 static int
113 ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS)
114 {
115 	int error, value = 0;
116 
117 	state_hash_size_old = state_hash_size;
118 	value = state_hash_size;
119 	error = sysctl_handle_int(oidp, &value, 0, req);
120 	if (error || !req->newptr) {
121 		goto back;
122 	}
123 	/*
124 	 * Make sure we have a power of 2 and
125 	 * do not allow more than 64k entries.
126 	 */
127 	error = EINVAL;
128 	if (value <= 1 || value > 65536) {
129 		goto back;
130 	}
131 	if ((value & (value - 1)) != 0) {
132 		goto back;
133 	}
134 
135 	error = 0;
136 	if (state_hash_size != value) {
137 		state_hash_size = value;
138 
139 		struct netmsg_base *msg, the_msg;
140 		msg = &the_msg;
141 		bzero(msg,sizeof(struct netmsg_base));
142 
143 		netmsg_init(msg, NULL, &curthread->td_msgport,
144 				0, adjust_hash_size_dispatch);
145 		netisr_domsg(msg, 0);
146 	}
147 back:
148 	return error;
149 }
150 
151 void
152 adjust_hash_size_dispatch(netmsg_t nmsg)
153 {
154 	struct ipfw_state_context *state_ctx;
155 	struct ip_fw_state *the_state, *state;
156 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
157 	int i;
158 
159 	for (i = 0; i < state_hash_size_old; i++) {
160 		state_ctx = &ctx->state_ctx[i];
161 		if (state_ctx != NULL) {
162 			state = state_ctx->state;
163 			while (state != NULL) {
164 				the_state = state;
165 				state = state->next;
166 				kfree(the_state, M_IPFW3_BASIC);
167 				the_state = NULL;
168 			}
169 		}
170 	}
171 	kfree(ctx->state_ctx,M_IPFW3_BASIC);
172 	ctx->state_ctx = kmalloc(state_hash_size *
173 				sizeof(struct ipfw_state_context),
174 				M_IPFW3_BASIC, M_WAITOK | M_ZERO);
175 	ctx->state_hash_size = state_hash_size;
176 	netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
177 }
178 
179 
180 /*	prototype of the checker functions	*/
181 void check_count(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_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
184 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
185 void check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
186 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
187 void check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
188 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
189 
190 void check_in(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_out(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_via(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_proto(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_prob(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(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_lookup(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_from_me(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_from_mask(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(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_lookup(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_to_me(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_to_mask(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_keep_state(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_tag(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_untag(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_tagged(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_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_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 void check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
229 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
230 void check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
231 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
232 
233 /*	prototype of the utility functions	*/
234 int match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid,
235 	struct ip_fw_state *state);
236 int count_match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid,
237 	struct ip_fw_state *state, int *count);
238 
239 static struct ip_fw *lookup_next_rule(struct ip_fw *me);
240 static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd);
241 static __inline int hash_packet(struct ipfw_flow_id *id);
242 
243 static __inline int
244 hash_packet(struct ipfw_flow_id *id)
245 {
246 	uint32_t i;
247 	i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^
248 		(id->dst_port) ^ (id->src_port);
249 	i &= state_hash_size - 1;
250 	return i;
251 }
252 
253 static struct ip_fw *
254 lookup_next_rule(struct ip_fw *me)
255 {
256 	struct ip_fw *rule = NULL;
257 	ipfw_insn *cmd;
258 
259 	/* look for action, in case it is a skipto */
260 	cmd = ACTION_PTR(me);
261 	if ((int)cmd->module == MODULE_BASIC_ID &&
262 		(int)cmd->opcode == O_BASIC_SKIPTO) {
263 		for (rule = me->next; rule; rule = rule->next) {
264 			if (rule->rulenum >= cmd->arg1)
265 				break;
266 		}
267 	}
268 	if (rule == NULL) /* failure or not a skipto */
269 		rule = me->next;
270 
271 	me->next_rule = rule;
272 	return rule;
273 }
274 
275 /*
276  * return value
277  * 0 : not match  1: same direction 2: reverse direction
278  */
279 int
280 match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid, struct ip_fw_state *state)
281 {
282 	 if (fid->src_ip == state->flow_id.src_ip &&
283 		 fid->dst_ip == state->flow_id.dst_ip &&
284 		 (fid->src_port == state->flow_id.src_port ||
285 				 state->flow_id.src_port == 0) &&
286 		 (fid->dst_port == state->flow_id.dst_port ||
287 				 state->flow_id.dst_port == 0)) {
288 		 return 1;
289 	 }
290 	 if (fid->src_ip == state->flow_id.dst_ip &&
291 		 fid->dst_ip == state->flow_id.src_ip &&
292 		 (fid->src_port == state->flow_id.dst_port ||
293 				 state->flow_id.dst_port == 0) &&
294 		 (fid->dst_port == state->flow_id.src_port ||
295 				 state->flow_id.src_port == 0)) {
296 		 return 2;
297 	 }
298 	 return 0;
299 }
300 
301 /*
302  * return 1 when more states than limit
303  * arg3: limit type (1=src ip, 2=src port, 3=dst ip, 4=dst port)
304  * arg1: limit
305  */
306 int
307 count_match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid,
308 	struct ip_fw_state *state, int *count)
309 {
310 	 if ((cmd->arg3 == 1 && fid->src_ip == state->flow_id.src_ip) ||
311 		 (cmd->arg3 == 2 && fid->src_port == state->flow_id.src_port) ||
312 		 (cmd->arg3 == 3 && fid->dst_ip == state->flow_id.dst_ip) ||
313 		 (cmd->arg3 == 4 && fid->dst_port == state->flow_id.dst_port)) {
314 		 *count = *count + 1;
315 		 if (*count >= cmd->arg1)
316 			 return 1;
317 	 }
318 	  return 0;
319 }
320 
321 /*
322  * when all = 1, it will check all the state_ctx
323  * all = 1 during keep-state
324  * all = 0 during check-state
325  *
326  * in the cmd of keep_state
327  * arg3=type arg1=limit
328  */
329 static struct ip_fw_state *
330 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all)
331 {
332 	struct ip_fw_state *state = NULL;
333 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
334 	struct ipfw_state_context *state_ctx;
335 	int start, end, i, count = 0;
336 
337 	if (all && cmd->arg1) {
338 		start = 0;
339 		end = state_hash_size - 1;
340 	} else {
341 		start = hash_packet(&args->f_id);
342 		end = hash_packet(&args->f_id);
343 	}
344 
345 	for (i = start; i <= end; i++) {
346 		state_ctx = &ctx->state_ctx[i];
347 		if (state_ctx != NULL) {
348 			state = state_ctx->state;
349 			struct ipfw_flow_id	*fid = &args->f_id;
350 			while (state != NULL) {
351 				/* has limit and already exceed the limit */
352 				if (cmd->arg1 &&
353 					count_match_state(cmd, fid,
354 							state, &count) != 0) {
355 					*limited = 1;
356 					 goto done;
357 				 }
358 
359 				if (fid->proto == state->flow_id.proto &&
360 						 match_state(cmd, fid, state) != 0)
361 					 goto done;
362 
363 				state = state->next;
364 			}
365 		}
366 	}
367 done:
368 	return state;
369 }
370 
371 static struct ip_fw_state *
372 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args)
373 {
374 	struct ip_fw_state *state;
375 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
376 	struct ipfw_state_context *state_ctx;
377 	int hash = hash_packet(&args->f_id);
378 	state_ctx = &ctx->state_ctx[hash];
379 	state = kmalloc(sizeof(struct ip_fw_state),
380 			M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
381 	if (state == NULL) {
382 		return NULL;
383 	}
384 	state->stub = rule;
385 	state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ;
386 	state->timestamp = time_second;
387 	state->expiry = 0;
388 	bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id));
389 	//append the state into the state chian
390 	if (state_ctx->last != NULL)
391 		state_ctx->last->next = state;
392 	else
393 		state_ctx->state = state;
394 	state_ctx->last = state;
395 	state_ctx->count++;
396 
397 	if (sync_ctx.running & 2) {
398 		ipfw_sync_send_state_prt(state, mycpuid, hash);
399 	}
400 	return state;
401 }
402 
403 void
404 ipfw_sync_install_state(struct cmd_send_state *cmd)
405 {
406         struct ip_fw_state *state;
407         struct ipfw_context *ctx = ipfw_ctx[cmd->cpu];
408         struct ipfw_state_context *state_ctx;
409         struct ip_fw *rule;
410 
411         state_ctx = &ctx->state_ctx[cmd->hash];
412         state = kmalloc(sizeof(struct ip_fw_state),
413                         M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
414         if (state == NULL) {
415                 return;
416         }
417         for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
418                 if (rule->rulenum == cmd->rulenum) {
419                         goto found;
420                 }
421         }
422         return;
423 found:
424         state->stub = rule;
425         state->lifetime = cmd->lifetime;
426         state->timestamp = time_second;
427         state->expiry = 0;
428         bcopy(&cmd->flow, &state->flow_id, sizeof(struct ipfw_flow_id));
429         //append the state into the state chian
430         if (state_ctx->last != NULL)
431                 state_ctx->last->next = state;
432         else
433                 state_ctx->state = state;
434         state_ctx->last = state;
435         state_ctx->count++;
436 }
437 
438 static int
439 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
440 {
441 	if (ifp == NULL)	/* no iface with this packet, match fails */
442 		return 0;
443 
444 	/* Check by name or by IP address */
445 	if (cmd->name[0] != '\0') { /* match by name */
446 		/* Check name */
447 		if (cmd->p.glob) {
448 			if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
449 				return(1);
450 		} else {
451 			if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
452 				return(1);
453 		}
454 	} else {
455 		struct ifaddr_container *ifac;
456 
457 		TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
458 			struct ifaddr *ia = ifac->ifa;
459 
460 			if (ia->ifa_addr == NULL)
461 				continue;
462 			if (ia->ifa_addr->sa_family != AF_INET)
463 				continue;
464 			if (cmd->p.ip.s_addr ==
465 				((struct sockaddr_in *)
466 				(ia->ifa_addr))->sin_addr.s_addr)
467 					return(1);	/* match */
468 
469 		}
470 	}
471 	return 0;	/* no match, fail ... */
472 }
473 
474 /* implimentation of the checker functions */
475 void
476 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
477 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
478 {
479 	(*f)->pcnt++;
480 	(*f)->bcnt += ip_len;
481 	(*f)->timestamp = time_second;
482 	*cmd_ctl = IP_FW_CTL_NEXT;
483 }
484 
485 void
486 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
487 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
488 {
489 	(*f)->pcnt++;
490 	(*f)->bcnt += ip_len;
491 	(*f)->timestamp = time_second;
492 	if ((*f)->next_rule == NULL)
493 		lookup_next_rule(*f);
494 	*f = (*f)->next_rule;
495 	*cmd_ctl = IP_FW_CTL_AGAIN;
496 }
497 
498 void
499 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
500 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
501 {
502 	struct sockaddr_in *sin, *sa;
503 	struct m_tag *mtag;
504 
505 	if ((*args)->eh) {	/* not valid on layer2 pkts */
506 		*cmd_ctl=IP_FW_CTL_NEXT;
507 		return;
508 	}
509 
510 	(*f)->pcnt++;
511 	(*f)->bcnt += ip_len;
512 	(*f)->timestamp = time_second;
513 	if ((*f)->next_rule == NULL)
514 		lookup_next_rule(*f);
515 
516 	mtag = m_tag_get(PACKET_TAG_IPFORWARD,
517 			sizeof(*sin), M_INTWAIT | M_NULLOK);
518 	if (mtag == NULL) {
519 		*cmd_val = IP_FW_DENY;
520 		*cmd_ctl = IP_FW_CTL_DONE;
521 		return;
522 	}
523 	sin = m_tag_data(mtag);
524 	sa = &((ipfw_insn_sa *)cmd)->sa;
525 	/* arg3: count of the dest, arg1: type of fwd */
526 	int i = 0;
527 	if(cmd->arg3 > 1) {
528 		if (cmd->arg1 == 0) {		/* type: random */
529 			i = krandom() % cmd->arg3;
530 		} else if (cmd->arg1 == 1) {	/* type: round-robin */
531 			i = cmd->arg2++ % cmd->arg3;
532 		} else if (cmd->arg1 == 2) {	/* type: sticky */
533 			struct ip *ip = mtod((*args)->m, struct ip *);
534 			i = ip->ip_src.s_addr & (cmd->arg3 - 1);
535 		}
536 		sa += i;
537 	}
538 	*sin = *sa;	/* apply the destination */
539 	m_tag_prepend((*args)->m, mtag);
540 	(*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED;
541 	(*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
542 	*cmd_ctl = IP_FW_CTL_DONE;
543 	*cmd_val = IP_FW_PASS;
544 }
545 
546 void
547 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
548 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
549 {
550 	struct ip_fw_state *state=NULL;
551 	int limited = 0 ;
552 	state = lookup_state(*args, cmd, &limited, 0);
553 	if (state != NULL) {
554 		state->pcnt++;
555 		state->bcnt += ip_len;
556 		state->timestamp = time_second;
557 		(*f)->pcnt++;
558 		(*f)->bcnt += ip_len;
559 		(*f)->timestamp = time_second;
560 		*f = state->stub;
561 		*cmd_ctl = IP_FW_CTL_CHK_STATE;
562 	} else {
563 		*cmd_ctl = IP_FW_CTL_NEXT;
564 	}
565 }
566 
567 void
568 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
569 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
570 {
571 	*cmd_ctl = IP_FW_CTL_NO;
572 	*cmd_val = ((*args)->oif == NULL);
573 }
574 
575 void
576 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
577 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
578 {
579 	*cmd_ctl = IP_FW_CTL_NO;
580 	*cmd_val = ((*args)->oif != NULL);
581 }
582 
583 void
584 check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
585 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
586 {
587 	*cmd_ctl = IP_FW_CTL_NO;
588 	*cmd_val = iface_match((*args)->oif ?
589 			(*args)->oif : (*args)->m->m_pkthdr.rcvif,
590 			(ipfw_insn_if *)cmd);
591 }
592 
593 void
594 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
595 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
596 {
597 	*cmd_ctl = IP_FW_CTL_NO;
598 	*cmd_val = ((*args)->f_id.proto == cmd->arg1);
599 }
600 
601 void
602 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
603 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
604 {
605 	*cmd_ctl = IP_FW_CTL_NO;
606 	*cmd_val = (krandom() % 100) < cmd->arg1;
607 }
608 
609 void
610 check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
611 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
612 {
613 	struct in_addr src_ip;
614 	u_int hlen = 0;
615 	struct mbuf *m = (*args)->m;
616 	struct ip *ip = mtod(m, struct ip *);
617 	src_ip = ip->ip_src;
618 	if ((*args)->eh == NULL ||
619 		(m->m_pkthdr.len >= sizeof(struct ip) &&
620 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
621 		hlen = ip->ip_hl << 2;
622 	}
623 	*cmd_val = (hlen > 0 &&
624 			((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
625 	*cmd_ctl = IP_FW_CTL_NO;
626 }
627 
628 void
629 check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
630 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
631 {
632 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
633 	struct ipfw_table_context *table_ctx;
634 	struct radix_node_head *rnh;
635 	struct sockaddr_in sa;
636 
637 	struct mbuf *m = (*args)->m;
638 	struct ip *ip = mtod(m, struct ip *);
639 	struct in_addr src_ip = ip->ip_src;
640 
641 	*cmd_val = IP_FW_NOT_MATCH;
642 
643 	table_ctx = ctx->table_ctx;
644 	table_ctx += cmd->arg1;
645 
646         if (table_ctx->type != 0) {
647                 rnh = table_ctx->node;
648                 sa.sin_len = 8;
649                 sa.sin_addr.s_addr = src_ip.s_addr;
650                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
651                         *cmd_val = IP_FW_MATCH;
652         }
653 	*cmd_ctl = IP_FW_CTL_NO;
654 }
655 
656 void
657 check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
658 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
659 {
660 	struct in_addr src_ip;
661 	u_int hlen = 0;
662 	struct mbuf *m = (*args)->m;
663 	struct ip *ip = mtod(m, struct ip *);
664 	src_ip = ip->ip_src;
665 	if ((*args)->eh == NULL ||
666 		(m->m_pkthdr.len >= sizeof(struct ip) &&
667 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
668 		hlen = ip->ip_hl << 2;
669 	}
670 	*cmd_ctl = IP_FW_CTL_NO;
671 	if (hlen > 0) {
672 		struct ifnet *tif;
673 		tif = INADDR_TO_IFP(&src_ip);
674 		*cmd_val = (tif != NULL);
675 	} else {
676 		*cmd_val = IP_FW_NOT_MATCH;
677 	}
678 }
679 
680 void
681 check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
682 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
683 {
684 	struct in_addr src_ip;
685 	u_int hlen = 0;
686 	struct mbuf *m = (*args)->m;
687 	struct ip *ip = mtod(m, struct ip *);
688 	src_ip = ip->ip_src;
689 	if ((*args)->eh == NULL ||
690 		(m->m_pkthdr.len >= sizeof(struct ip) &&
691 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
692 		hlen = ip->ip_hl << 2;
693 	}
694 
695 	*cmd_ctl = IP_FW_CTL_NO;
696 	*cmd_val = (hlen > 0 &&
697 			((ipfw_insn_ip *)cmd)->addr.s_addr ==
698 			(src_ip.s_addr &
699 			((ipfw_insn_ip *)cmd)->mask.s_addr));
700 }
701 
702 void
703 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
704 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
705 {
706 	struct in_addr dst_ip;
707 	u_int hlen = 0;
708 	struct mbuf *m = (*args)->m;
709 	struct ip *ip = mtod(m, struct ip *);
710 	dst_ip = ip->ip_dst;
711 	if ((*args)->eh == NULL ||
712 		(m->m_pkthdr.len >= sizeof(struct ip) &&
713 		 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
714 		hlen = ip->ip_hl << 2;
715 	}
716 	*cmd_val = (hlen > 0 &&
717 			((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
718 	*cmd_ctl = IP_FW_CTL_NO;
719 }
720 
721 void
722 check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
723 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
724 {
725 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
726 	struct ipfw_table_context *table_ctx;
727 	struct radix_node_head *rnh;
728 	struct sockaddr_in sa;
729 
730 	struct mbuf *m = (*args)->m;
731 	struct ip *ip = mtod(m, struct ip *);
732 	struct in_addr dst_ip = ip->ip_dst;
733 
734 	*cmd_val = IP_FW_NOT_MATCH;
735 
736 	table_ctx = ctx->table_ctx;
737 	table_ctx += cmd->arg1;
738 
739         if (table_ctx->type != 0) {
740                 rnh = table_ctx->node;
741                 sa.sin_len = 8;
742                 sa.sin_addr.s_addr = dst_ip.s_addr;
743                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
744                         *cmd_val = IP_FW_MATCH;
745         }
746 	*cmd_ctl = IP_FW_CTL_NO;
747 }
748 
749 void
750 check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
751 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
752 {
753 	struct in_addr dst_ip;
754 	u_int hlen = 0;
755 	struct mbuf *m = (*args)->m;
756 	struct ip *ip = mtod(m, struct ip *);
757 	dst_ip = ip->ip_src;
758 	if ((*args)->eh == NULL ||
759 		(m->m_pkthdr.len >= sizeof(struct ip) &&
760 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
761 		hlen = ip->ip_hl << 2;
762 	}
763 	*cmd_ctl = IP_FW_CTL_NO;
764 	if (hlen > 0) {
765 		struct ifnet *tif;
766 		tif = INADDR_TO_IFP(&dst_ip);
767 		*cmd_val = (tif != NULL);
768 	} else {
769 		*cmd_val = IP_FW_NOT_MATCH;
770 	}
771 }
772 
773 void
774 check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
775 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
776 {
777 	struct in_addr dst_ip;
778 	u_int hlen = 0;
779 	struct mbuf *m = (*args)->m;
780 	struct ip *ip = mtod(m, struct ip *);
781 	dst_ip = ip->ip_src;
782 	if ((*args)->eh == NULL ||
783 		(m->m_pkthdr.len >= sizeof(struct ip) &&
784 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
785 		hlen = ip->ip_hl << 2;
786 	}
787 
788 	*cmd_ctl = IP_FW_CTL_NO;
789 	*cmd_val = (hlen > 0 &&
790 			((ipfw_insn_ip *)cmd)->addr.s_addr ==
791 			(dst_ip.s_addr &
792 			((ipfw_insn_ip *)cmd)->mask.s_addr));
793 }
794 
795 void
796 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
797 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
798 {
799 	struct ip_fw_state *state;
800 	int limited = 0;
801 
802 	*cmd_ctl = IP_FW_CTL_NO;
803 	*cmd_val = IP_FW_MATCH;
804 	state = lookup_state(*args, cmd, &limited, 1);
805 	if (limited != 1) {
806 		if (state == NULL)
807 			state = install_state(*f, cmd, *args);
808 
809 		if (state != NULL) {
810 			state->pcnt++;
811 			state->bcnt += ip_len;
812 			state->timestamp = time_second;
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 	netisr_forwardmsg_all(&nmsg->base, 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 
1066 static void
1067 ipfw_tick_dispatch(netmsg_t nmsg)
1068 {
1069 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1070 	KKASSERT(IPFW_BASIC_LOADED);
1071 
1072 	/* Reply ASAP */
1073 	crit_enter();
1074 	lwkt_replymsg(&nmsg->lmsg, 0);
1075 	crit_exit();
1076 
1077 	callout_reset(&ipfw_tick_callout,
1078 			state_expiry_check_interval * hz, ipfw_tick, NULL);
1079 
1080 	struct netmsg_base msg;
1081 	netmsg_init(&msg, NULL, &curthread->td_msgport, 0,
1082 			ipfw_cleanup_expired_state);
1083 	netisr_domsg(&msg, 0);
1084 }
1085 
1086 static void
1087 ipfw_basic_init_dispatch(netmsg_t nmsg)
1088 {
1089 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1090 	KKASSERT(IPFW3_LOADED);
1091 
1092 	int error = 0;
1093 	callout_init_mp(&ipfw_tick_callout);
1094 	netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport,
1095 			MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch);
1096 	callout_reset(&ipfw_tick_callout,
1097 			state_expiry_check_interval * hz, ipfw_tick, NULL);
1098 	lwkt_replymsg(&nmsg->lmsg, error);
1099 	ip_fw_basic_loaded=1;
1100 }
1101 
1102 static int
1103 ipfw_basic_init(void)
1104 {
1105 	ipfw_basic_flush_state_prt = ipfw_basic_flush_state;
1106 	ipfw_basic_append_state_prt = ipfw_basic_add_state;
1107 	ipfw_sync_install_state_prt = ipfw_sync_install_state;
1108 
1109 	register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME);
1110 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT,
1111 			(filter_func)check_count);
1112 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO,
1113 			(filter_func)check_skipto);
1114 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD,
1115 			(filter_func)check_forward);
1116 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
1117 			(filter_func)check_keep_state);
1118 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
1119 			(filter_func)check_check_state);
1120 
1121 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1122 			O_BASIC_IN, (filter_func)check_in);
1123 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1124 			O_BASIC_OUT, (filter_func)check_out);
1125 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1126 			O_BASIC_VIA, (filter_func)check_via);
1127 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1128 			O_BASIC_XMIT, (filter_func)check_via);
1129 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1130 			O_BASIC_RECV, (filter_func)check_via);
1131 
1132 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1133 			O_BASIC_PROTO, (filter_func)check_proto);
1134 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1135 			O_BASIC_PROB, (filter_func)check_prob);
1136 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1137 			O_BASIC_IP_SRC, (filter_func)check_from);
1138 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1139 			O_BASIC_IP_SRC_LOOKUP, (filter_func)check_from_lookup);
1140 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1141 			O_BASIC_IP_SRC_ME, (filter_func)check_from_me);
1142 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1143 			O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask);
1144 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1145 			O_BASIC_IP_DST, (filter_func)check_to);
1146 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1147 			O_BASIC_IP_DST_LOOKUP, (filter_func)check_to_lookup);
1148 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1149 			O_BASIC_IP_DST_ME, (filter_func)check_to_me);
1150 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1151 			O_BASIC_IP_DST_MASK, (filter_func)check_to_mask);
1152 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1153 			O_BASIC_TAG, (filter_func)check_tag);
1154 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1155 			O_BASIC_UNTAG, (filter_func)check_untag);
1156 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1157 			O_BASIC_TAGGED, (filter_func)check_tagged);
1158 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1159 			O_BASIC_IP_SRCPORT, (filter_func)check_src_port);
1160 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1161 			O_BASIC_IP_DSTPORT, (filter_func)check_dst_port);
1162 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1163 			O_BASIC_IP_SRC_N_PORT, (filter_func)check_src_n_port);
1164 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1165 			O_BASIC_IP_DST_N_PORT, (filter_func)check_dst_n_port);
1166 
1167 	int cpu;
1168 	struct ipfw_context *ctx;
1169 
1170 	for (cpu = 0; cpu < ncpus; cpu++) {
1171 		ctx = ipfw_ctx[cpu];
1172 		if (ctx != NULL) {
1173 			ctx->state_ctx = kmalloc(state_hash_size *
1174 					sizeof(struct ipfw_state_context),
1175 					M_IPFW3_BASIC, M_WAITOK | M_ZERO);
1176 			ctx->state_hash_size = state_hash_size;
1177 		}
1178 	}
1179 
1180 	struct netmsg_base smsg;
1181 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
1182 			0, ipfw_basic_init_dispatch);
1183 	lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1184 	return 0;
1185 }
1186 
1187 static void
1188 ipfw_basic_stop_dispatch(netmsg_t nmsg)
1189 {
1190 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1191 	KKASSERT(IPFW3_LOADED);
1192 	int error = 0;
1193 	callout_stop(&ipfw_tick_callout);
1194 	netmsg_service_sync();
1195 	crit_enter();
1196 	lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg);
1197 	crit_exit();
1198 	lwkt_replymsg(&nmsg->lmsg, error);
1199 	ip_fw_basic_loaded=0;
1200 }
1201 
1202 static int
1203 ipfw_basic_stop(void)
1204 {
1205 	int cpu,i;
1206 	struct ipfw_state_context *state_ctx;
1207 	struct ip_fw_state *state,*the_state;
1208 	struct ipfw_context *ctx;
1209 	if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) {
1210 		ipfw_basic_flush_state_prt = NULL;
1211 		ipfw_basic_append_state_prt = NULL;
1212 
1213 		for (cpu = 0; cpu < ncpus; cpu++) {
1214 			ctx = ipfw_ctx[cpu];
1215 			if (ctx != NULL) {
1216 				for (i = 0; i < state_hash_size; i++) {
1217 					state_ctx = &ctx->state_ctx[i];
1218 					if (state_ctx != NULL) {
1219 						state = state_ctx->state;
1220 						while (state != NULL) {
1221 							the_state = state;
1222 							state = state->next;
1223 							if (the_state ==
1224 								state_ctx->last)
1225 							state_ctx->last = NULL;
1226 
1227 							kfree(the_state,
1228 								M_IPFW3_BASIC);
1229 						}
1230 					}
1231 				}
1232 				ctx->state_hash_size = 0;
1233 				kfree(ctx->state_ctx, M_IPFW3_BASIC);
1234 				ctx->state_ctx = NULL;
1235 			}
1236 		}
1237 		struct netmsg_base smsg;
1238 		netmsg_init(&smsg, NULL, &curthread->td_msgport,
1239 				0, ipfw_basic_stop_dispatch);
1240 		return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1241 	}
1242 	return 1;
1243 }
1244 
1245 
1246 static int
1247 ipfw3_basic_modevent(module_t mod, int type, void *data)
1248 {
1249 	int err;
1250 	switch (type) {
1251 		case MOD_LOAD:
1252 			err = ipfw_basic_init();
1253 			break;
1254 		case MOD_UNLOAD:
1255 			err = ipfw_basic_stop();
1256 			break;
1257 		default:
1258 			err = 1;
1259 	}
1260 	return err;
1261 }
1262 
1263 static moduledata_t ipfw3_basic_mod = {
1264 	"ipfw3_basic",
1265 	ipfw3_basic_modevent,
1266 	NULL
1267 };
1268 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
1269 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1);
1270 MODULE_VERSION(ipfw3_basic, 1);
1271