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 
70 #include "ip_fw3_basic.h"
71 
72 #define TIME_LEQ(a, b)	((int)((a) - (b)) <= 0)
73 
74 extern struct ipfw_context	*ipfw_ctx[MAXCPU];
75 extern int fw_verbose;
76 extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt;
77 extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt;
78 
79 static int ip_fw_basic_loaded;
80 static struct netmsg_base ipfw_timeout_netmsg;	/* schedule ipfw timeout */
81 static struct callout ipfw_tick_callout;
82 static int state_lifetime = 20;
83 static int state_expiry_check_interval = 10;
84 static int state_count_max = 4096;
85 static int state_hash_size_old = 0;
86 static int state_hash_size = 4096;
87 
88 
89 static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS);
90 void adjust_hash_size_dispatch(netmsg_t nmsg);
91 
92 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic,
93 		CTLFLAG_RW, 0, "Firewall Basic");
94 SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size,
95 		CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0,
96 		ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size");
97 
98 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW,
99 		&state_lifetime, 0, "default life time");
100 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO,
101 		state_expiry_check_interval, CTLFLAG_RW,
102 		&state_expiry_check_interval, 0,
103 		"default state expiry check interval");
104 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW,
105 		&state_count_max, 0, "maximum of state");
106 
107 static int
108 ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS)
109 {
110 	int error, value = 0;
111 
112 	state_hash_size_old = state_hash_size;
113 	value = state_hash_size;
114 	error = sysctl_handle_int(oidp, &value, 0, req);
115 	if (error || !req->newptr) {
116 		goto back;
117 	}
118 	/*
119 	 * Make sure we have a power of 2 and
120 	 * do not allow more than 64k entries.
121 	 */
122 	error = EINVAL;
123 	if (value <= 1 || value > 65536) {
124 		goto back;
125 	}
126 	if ((value & (value - 1)) != 0) {
127 		goto back;
128 	}
129 
130 	error = 0;
131 	if (state_hash_size != value) {
132 		state_hash_size = value;
133 
134 		struct netmsg_base *msg, the_msg;
135 		msg = &the_msg;
136 		bzero(msg,sizeof(struct netmsg_base));
137 
138 		netmsg_init(msg, NULL, &curthread->td_msgport,
139 				0, adjust_hash_size_dispatch);
140 		ifnet_domsg(&msg->lmsg, 0);
141 	}
142 back:
143 	return error;
144 }
145 
146 void
147 adjust_hash_size_dispatch(netmsg_t nmsg)
148 {
149 	struct ipfw_state_context *state_ctx;
150 	struct ip_fw_state *the_state, *state;
151 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
152 	int i;
153 
154 	for (i = 0; i < state_hash_size_old; i++) {
155 		state_ctx = &ctx->state_ctx[i];
156 		if (state_ctx != NULL) {
157 			state = state_ctx->state;
158 			while (state != NULL) {
159 				the_state = state;
160 				state = state->next;
161 				kfree(the_state, M_IPFW3_BASIC);
162 				the_state = NULL;
163 			}
164 		}
165 	}
166 	kfree(ctx->state_ctx,M_IPFW3_BASIC);
167 	ctx->state_ctx = kmalloc(state_hash_size *
168 				sizeof(struct ipfw_state_context),
169 				M_IPFW3_BASIC, M_WAITOK | M_ZERO);
170 	ctx->state_hash_size = state_hash_size;
171 	ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
172 }
173 
174 
175 /*	prototype of the checker functions	*/
176 void check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
177 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
178 void check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
179 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
180 void check_forward(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_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
183 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
184 
185 void check_in(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_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
188 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
189 void check_via(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_proto(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_prob(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_from(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_to(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_keep_state(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_tag(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_untag(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_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
206 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
207 
208 /*	prototype of the utility functions	*/
209 static struct ip_fw *lookup_next_rule(struct ip_fw *me);
210 static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd);
211 static __inline int hash_packet(struct ipfw_flow_id *id);
212 
213 static __inline int
214 hash_packet(struct ipfw_flow_id *id)
215 {
216 	uint32_t i;
217 	i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^
218 		(id->dst_port) ^ (id->src_port);
219 	i &= state_hash_size - 1;
220 	return i;
221 }
222 
223 static struct ip_fw *
224 lookup_next_rule(struct ip_fw *me)
225 {
226 	struct ip_fw *rule = NULL;
227 	ipfw_insn *cmd;
228 
229 	/* look for action, in case it is a skipto */
230 	cmd = ACTION_PTR(me);
231 	if ((int)cmd->module == MODULE_BASIC_ID &&
232 		(int)cmd->opcode == O_BASIC_SKIPTO) {
233 		for (rule = me->next; rule; rule = rule->next) {
234 			if (rule->rulenum >= cmd->arg1)
235 				break;
236 		}
237 	}
238 	if (rule == NULL) /* failure or not a skipto */
239 		rule = me->next;
240 
241 	me->next_rule = rule;
242 	return rule;
243 }
244 
245 /*
246  * when all = 1, it will check all the state_ctx
247  */
248 static struct ip_fw_state *
249 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all)
250 {
251 	struct ip_fw_state *state = NULL;
252 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
253 	struct ipfw_state_context *state_ctx;
254 	int start, end, i, count = 0;
255 
256 	if (all && cmd->arg1) {
257 		start = 0;
258 		end = state_hash_size - 1;
259 	} else {
260 		start = hash_packet(&args->f_id);
261 		end = hash_packet(&args->f_id);
262 	}
263 	for (i = start; i <= end; i++) {
264 		state_ctx = &ctx->state_ctx[i];
265 		if (state_ctx != NULL) {
266 			state = state_ctx->state;
267 			struct ipfw_flow_id	*fid = &args->f_id;
268 			while (state != NULL) {
269 				if (cmd->arg1) {
270 					if ((cmd->arg3 == 1 &&
271 						fid->src_ip ==
272 						state->flow_id.src_ip) ||
273 						(cmd->arg3 == 2 &&
274 						fid->src_port ==
275 						state->flow_id.src_port) ||
276 						(cmd->arg3 == 3 &&
277 						fid->dst_ip ==
278 						state->flow_id.dst_ip) ||
279 						(cmd->arg3 == 4 &&
280 						fid->dst_port ==
281 						state->flow_id.dst_port)) {
282 
283 						count++;
284 						if (count >= cmd->arg1) {
285 							*limited = 1;
286 							goto done;
287 						}
288 					}
289 				}
290 
291 				if (fid->proto == state->flow_id.proto) {
292 					if (fid->src_ip ==
293 					state->flow_id.src_ip &&
294 					fid->dst_ip ==
295 					state->flow_id.dst_ip &&
296 					(fid->src_port ==
297 					state->flow_id.src_port ||
298 					state->flow_id.src_port == 0) &&
299 					(fid->dst_port ==
300 					state->flow_id.dst_port ||
301 					state->flow_id.dst_port == 0)) {
302 						goto done;
303 					}
304 					if (fid->src_ip ==
305 					state->flow_id.dst_ip &&
306 					fid->dst_ip ==
307 					state->flow_id.src_ip &&
308 					(fid->src_port ==
309 					state->flow_id.dst_port ||
310 					state->flow_id.dst_port == 0) &&
311 					(fid->dst_port ==
312 					state->flow_id.src_port ||
313 					state->flow_id.src_port == 0)) {
314 						goto done;
315 					}
316 				}
317 				state = state->next;
318 			}
319 		}
320 	}
321 done:
322 	return state;
323 }
324 
325 static struct ip_fw_state *
326 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args)
327 {
328 	struct ip_fw_state *state;
329 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
330 	struct ipfw_state_context *state_ctx;
331 	state_ctx = &ctx->state_ctx[hash_packet(&args->f_id)];
332 	state = kmalloc(sizeof(struct ip_fw_state),
333 			M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
334 	if (state == NULL) {
335 		return NULL;
336 	}
337 	state->stub = rule;
338 	state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ;
339 	state->timestamp = time_second;
340 	state->expiry = 0;
341 	bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id));
342 	//append the state into the state chian
343 	if (state_ctx->last != NULL)
344 		state_ctx->last->next = state;
345 	else
346 		state_ctx->state = state;
347 	state_ctx->last = state;
348 	state_ctx->count++;
349 	return state;
350 }
351 
352 
353 static int
354 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
355 {
356 	if (ifp == NULL)	/* no iface with this packet, match fails */
357 		return 0;
358 
359 	/* Check by name or by IP address */
360 	if (cmd->name[0] != '\0') { /* match by name */
361 		/* Check name */
362 		if (cmd->p.glob) {
363 			if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
364 				return(1);
365 		} else {
366 			if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
367 				return(1);
368 		}
369 	} else {
370 		struct ifaddr_container *ifac;
371 
372 		TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
373 			struct ifaddr *ia = ifac->ifa;
374 
375 			if (ia->ifa_addr == NULL)
376 				continue;
377 			if (ia->ifa_addr->sa_family != AF_INET)
378 				continue;
379 			if (cmd->p.ip.s_addr ==
380 				((struct sockaddr_in *)
381 				(ia->ifa_addr))->sin_addr.s_addr)
382 					return(1);	/* match */
383 
384 		}
385 	}
386 	return 0;	/* no match, fail ... */
387 }
388 
389 /* implimentation of the checker functions */
390 void
391 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
392 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
393 {
394 	(*f)->pcnt++;
395 	(*f)->bcnt += ip_len;
396 	(*f)->timestamp = time_second;
397 	*cmd_ctl = IP_FW_CTL_NEXT;
398 }
399 
400 void
401 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
402 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
403 {
404 	(*f)->pcnt++;
405 	(*f)->bcnt += ip_len;
406 	(*f)->timestamp = time_second;
407 	if ((*f)->next_rule == NULL)
408 		lookup_next_rule(*f);
409 
410 	*cmd_ctl = IP_FW_CTL_AGAIN;
411 }
412 
413 void
414 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
415 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
416 {
417 	struct sockaddr_in *sin, *sa;
418 	struct m_tag *mtag;
419 
420 	if ((*args)->eh) {	/* not valid on layer2 pkts */
421 		*cmd_ctl=IP_FW_CTL_NEXT;
422 		return;
423 	}
424 
425 	(*f)->pcnt++;
426 	(*f)->bcnt += ip_len;
427 	(*f)->timestamp = time_second;
428 	if ((*f)->next_rule == NULL)
429 		lookup_next_rule(*f);
430 
431 	mtag = m_tag_get(PACKET_TAG_IPFORWARD,
432 			sizeof(*sin), M_NOWAIT);
433 	if (mtag == NULL) {
434 		*cmd_val = IP_FW_DENY;
435 		*cmd_ctl = IP_FW_CTL_DONE;
436 		return;
437 	}
438 	sin = m_tag_data(mtag);
439 	sa = &((ipfw_insn_sa *)cmd)->sa;
440 	/* arg3: count of the dest, arg1: type of fwd */
441 	int i = 0;
442 	if(cmd->arg3 > 1) {
443 		if (cmd->arg1 == 0) {		/* type: random */
444 			i = krandom() % cmd->arg3;
445 		} else if (cmd->arg1 == 1) {	/* type: round-robin */
446 			i = cmd->arg2++ % cmd->arg3;
447 		} else if (cmd->arg1 == 2) {	/* type: sticky */
448 			struct ip *ip = mtod((*args)->m, struct ip *);
449 			i = ip->ip_src.s_addr & (cmd->arg3 - 1);
450 		}
451 		sa += i;
452 	}
453 	*sin = *sa;	/* apply the destination */
454 	m_tag_prepend((*args)->m, mtag);
455 	(*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED;
456 	(*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
457 	*cmd_ctl = IP_FW_CTL_DONE;
458 	*cmd_val = IP_FW_PASS;
459 }
460 
461 void
462 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
463 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
464 {
465 	struct ip_fw_state *state=NULL;
466 	int limited = 0 ;
467 	state = lookup_state(*args, cmd, &limited, 0);
468 	if (state != NULL) {
469 		state->pcnt++;
470 		state->bcnt += ip_len;
471 		state->timestamp = time_second;
472 		(*f)->pcnt++;
473 		(*f)->bcnt += ip_len;
474 		(*f)->timestamp = time_second;
475 		*f = state->stub;
476 		*cmd_ctl = IP_FW_CTL_CHK_STATE;
477 	} else {
478 		*cmd_ctl = IP_FW_CTL_NEXT;
479 	}
480 }
481 
482 void
483 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
484 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
485 {
486 	*cmd_ctl = IP_FW_CTL_NO;
487 	*cmd_val = ((*args)->oif == NULL);
488 }
489 
490 void
491 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
492 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
493 {
494 	*cmd_ctl = IP_FW_CTL_NO;
495 	*cmd_val = ((*args)->oif != NULL);
496 }
497 
498 void
499 check_via(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 	*cmd_ctl = IP_FW_CTL_NO;
503 	*cmd_val = iface_match((*args)->oif ?
504 			(*args)->oif : (*args)->m->m_pkthdr.rcvif,
505 			(ipfw_insn_if *)cmd);
506 }
507 
508 void
509 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
510 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
511 {
512 	*cmd_ctl = IP_FW_CTL_NO;
513 	*cmd_val = ((*args)->f_id.proto == cmd->arg1);
514 }
515 
516 void
517 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
518 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
519 {
520 	*cmd_ctl = IP_FW_CTL_NO;
521 	*cmd_val = (krandom() % 100) < cmd->arg1;
522 }
523 
524 void
525 check_from(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 	struct in_addr src_ip;
529 	u_int hlen = 0;
530 	struct mbuf *m = (*args)->m;
531 	struct ip *ip = mtod(m, struct ip *);
532 	src_ip = ip->ip_src;
533 	if ((*args)->eh == NULL ||
534 		(m->m_pkthdr.len >= sizeof(struct ip) &&
535 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
536 		hlen = ip->ip_hl << 2;
537 	}
538 	*cmd_val = (hlen > 0 &&
539 			((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
540 	*cmd_ctl = IP_FW_CTL_NO;
541 }
542 
543 void
544 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
545 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
546 {
547 	struct in_addr dst_ip;
548 	u_int hlen = 0;
549 	struct mbuf *m = (*args)->m;
550 	struct ip *ip = mtod(m, struct ip *);
551 	dst_ip = ip->ip_dst;
552 	if ((*args)->eh == NULL ||
553 		(m->m_pkthdr.len >= sizeof(struct ip) &&
554 		 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
555 		hlen = ip->ip_hl << 2;
556 	}
557 	*cmd_val = (hlen > 0 &&
558 			((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
559 	*cmd_ctl = IP_FW_CTL_NO;
560 }
561 
562 void
563 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
564 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
565 {
566 	struct ip_fw_state *state;
567 	int limited = 0;
568 
569 	*cmd_ctl = IP_FW_CTL_NO;
570 	state = lookup_state(*args, cmd, &limited, 1);
571 	if (limited == 1) {
572 		*cmd_val = IP_FW_NOT_MATCH;
573 	} else {
574 		if (state == NULL)
575 			state = install_state(*f, cmd, *args);
576 
577 		if (state != NULL) {
578 			state->pcnt++;
579 			state->bcnt += ip_len;
580 			state->timestamp = time_second;
581 			*cmd_val = IP_FW_MATCH;
582 		} else {
583 			*cmd_val = IP_FW_NOT_MATCH;
584 		}
585 	}
586 }
587 
588 void
589 check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
590 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
591 {
592 	struct m_tag *mtag = m_tag_locate((*args)->m,
593 			MTAG_IPFW, cmd->arg1, NULL);
594 	if (mtag == NULL) {
595 		mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT);
596 		if (mtag != NULL)
597 			m_tag_prepend((*args)->m, mtag);
598 
599 	}
600 	(*f)->pcnt++;
601 	(*f)->bcnt += ip_len;
602 	(*f)->timestamp = time_second;
603 	*cmd_ctl = IP_FW_CTL_NEXT;
604 }
605 
606 void
607 check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
608 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
609 {
610 	struct m_tag *mtag = m_tag_locate((*args)->m,
611 			MTAG_IPFW, cmd->arg1, NULL);
612 	if (mtag != NULL)
613 		m_tag_delete((*args)->m, mtag);
614 
615 	(*f)->pcnt++;
616 	(*f)->bcnt += ip_len;
617 	(*f)->timestamp = time_second;
618 	*cmd_ctl = IP_FW_CTL_NEXT;
619 }
620 
621 void
622 check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
623 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
624 {
625 	*cmd_ctl = IP_FW_CTL_NO;
626 	if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL )
627 		*cmd_val = IP_FW_MATCH;
628 	else
629 		*cmd_val = IP_FW_NOT_MATCH;
630 }
631 
632 static void
633 ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state)
634 {
635 	struct ip_fw_state *state;
636 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
637 	struct ipfw_state_context *state_ctx;
638 	state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))];
639 	state = kmalloc(sizeof(struct ip_fw_state),
640 			M_IPFW3_BASIC, M_WAITOK | M_ZERO);
641 	struct ip_fw *rule = ctx->ipfw_rule_chain;
642 	while (rule != NULL) {
643 		if (rule->rulenum == ioc_state->rulenum) {
644 			break;
645 		}
646 		rule = rule->next;
647 	}
648 	if (rule == NULL)
649 		return;
650 
651 	state->stub = rule;
652 
653 	state->lifetime = ioc_state->lifetime == 0 ?
654 		state_lifetime : ioc_state->lifetime ;
655 	state->timestamp = time_second;
656 	state->expiry = ioc_state->expiry;
657 	bcopy(&ioc_state->flow_id, &state->flow_id,
658 			sizeof(struct ipfw_flow_id));
659 	//append the state into the state chian
660 	if (state_ctx->last != NULL)
661 		state_ctx->last->next = state;
662 	else
663 		state_ctx->state = state;
664 
665 	state_ctx->last = state;
666 	state_ctx->count++;
667 }
668 
669 /*
670  * if rule is NULL
671  * 		flush all states
672  * else
673  * 		flush states which stub is the rule
674  */
675 static void
676 ipfw_basic_flush_state(struct ip_fw *rule)
677 {
678 	struct ipfw_state_context *state_ctx;
679 	struct ip_fw_state *state,*the_state, *prev_state;
680 	struct ipfw_context *ctx;
681 	int i;
682 
683 	ctx = ipfw_ctx[mycpuid];
684 	for (i = 0; i < state_hash_size; i++) {
685 		state_ctx = &ctx->state_ctx[i];
686 		if (state_ctx != NULL) {
687 			state = state_ctx->state;
688 			prev_state = NULL;
689 			while (state != NULL) {
690 				if (rule != NULL && state->stub != rule) {
691 					prev_state = state;
692 					state = state->next;
693 				} else {
694 					if (prev_state == NULL)
695 						state_ctx->state = state->next;
696 					else
697 						prev_state->next = state->next;
698 
699 					the_state = state;
700 					state = state->next;
701 					kfree(the_state, M_IPFW3_BASIC);
702 					state_ctx->count--;
703 					if (state == NULL)
704 						state_ctx->last = prev_state;
705 
706 				}
707 			}
708 		}
709 	}
710 }
711 
712 /*
713  * clean up expired state in every tick
714  */
715 static void
716 ipfw_cleanup_expired_state(netmsg_t nmsg)
717 {
718 	struct ip_fw_state *state,*the_state,*prev_state;
719 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
720 	struct ipfw_state_context *state_ctx;
721 	int i;
722 
723 	for (i = 0; i < state_hash_size; i++) {
724 		prev_state = NULL;
725 		state_ctx = &(ctx->state_ctx[i]);
726 		if (ctx->state_ctx != NULL) {
727 			state = state_ctx->state;
728 			while (state != NULL) {
729 				if (IS_EXPIRED(state)) {
730 					if (prev_state == NULL)
731 						state_ctx->state = state->next;
732 					else
733 						prev_state->next = state->next;
734 
735 					the_state =state;
736 					state = state->next;
737 
738 					if (the_state == state_ctx->last)
739 						state_ctx->last = NULL;
740 
741 
742 					kfree(the_state, M_IPFW3_BASIC);
743 					state_ctx->count--;
744 				} else {
745 					prev_state = state;
746 					state = state->next;
747 				}
748 			}
749 		}
750 	}
751 	ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
752 }
753 
754 static void
755 ipfw_tick(void *dummy __unused)
756 {
757 	struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg;
758 	KKASSERT(mycpuid == IPFW_CFGCPUID);
759 
760 	crit_enter();
761 	KKASSERT(lmsg->ms_flags & MSGF_DONE);
762 	if (IPFW_BASIC_LOADED) {
763 		lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg);
764 		/* ipfw_timeout_netmsg's handler reset this callout */
765 	}
766 	crit_exit();
767 
768 	struct netmsg_base *msg;
769 	struct netmsg_base the_msg;
770 	msg = &the_msg;
771 	bzero(msg,sizeof(struct netmsg_base));
772 
773 	netmsg_init(msg, NULL, &curthread->td_msgport, 0,
774 			ipfw_cleanup_expired_state);
775 	ifnet_domsg(&msg->lmsg, 0);
776 }
777 
778 static void
779 ipfw_tick_dispatch(netmsg_t nmsg)
780 {
781 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
782 	KKASSERT(IPFW_BASIC_LOADED);
783 
784 	/* Reply ASAP */
785 	crit_enter();
786 	lwkt_replymsg(&nmsg->lmsg, 0);
787 	crit_exit();
788 
789 	callout_reset(&ipfw_tick_callout,
790 			state_expiry_check_interval * hz, ipfw_tick, NULL);
791 }
792 
793 static void
794 ipfw_basic_init_dispatch(netmsg_t nmsg)
795 {
796 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
797 	KKASSERT(IPFW3_LOADED);
798 
799 	int error = 0;
800 	callout_init_mp(&ipfw_tick_callout);
801 	netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport,
802 			MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch);
803 	callout_reset(&ipfw_tick_callout,
804 			state_expiry_check_interval * hz, ipfw_tick, NULL);
805 	lwkt_replymsg(&nmsg->lmsg, error);
806 	ip_fw_basic_loaded=1;
807 }
808 
809 static int
810 ipfw_basic_init(void)
811 {
812 	ipfw_basic_flush_state_prt = ipfw_basic_flush_state;
813 	ipfw_basic_append_state_prt = ipfw_basic_add_state;
814 
815 	register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME);
816 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT,
817 			(filter_func)check_count);
818 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO,
819 			(filter_func)check_skipto);
820 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD,
821 			(filter_func)check_forward);
822 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
823 			(filter_func)check_keep_state);
824 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
825 			(filter_func)check_check_state);
826 
827 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
828 			O_BASIC_IN, (filter_func)check_in);
829 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
830 			O_BASIC_OUT, (filter_func)check_out);
831 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
832 			O_BASIC_VIA, (filter_func)check_via);
833 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
834 			O_BASIC_XMIT, (filter_func)check_via);
835 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
836 			O_BASIC_RECV, (filter_func)check_via);
837 
838 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
839 			O_BASIC_PROTO, (filter_func)check_proto);
840 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
841 			O_BASIC_PROB, (filter_func)check_prob);
842 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
843 			O_BASIC_IP_SRC, (filter_func)check_from);
844 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
845 			O_BASIC_IP_DST, (filter_func)check_to);
846 
847 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
848 			O_BASIC_TAG, (filter_func)check_tag);
849 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
850 			O_BASIC_UNTAG, (filter_func)check_untag);
851 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
852 			O_BASIC_TAGGED, (filter_func)check_tagged);
853 
854 	int cpu;
855 	struct ipfw_context *ctx;
856 
857 	for (cpu = 0; cpu < ncpus; cpu++) {
858 		ctx = ipfw_ctx[cpu];
859 		if (ctx != NULL) {
860 			ctx->state_ctx = kmalloc(state_hash_size *
861 					sizeof(struct ipfw_state_context),
862 					M_IPFW3_BASIC, M_WAITOK | M_ZERO);
863 			ctx->state_hash_size = state_hash_size;
864 		}
865 	}
866 
867 	struct netmsg_base smsg;
868 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
869 			0, ipfw_basic_init_dispatch);
870 	lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
871 	return 0;
872 }
873 
874 static void
875 ipfw_basic_stop_dispatch(netmsg_t nmsg)
876 {
877 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
878 	KKASSERT(IPFW3_LOADED);
879 	int error = 0;
880 	callout_stop(&ipfw_tick_callout);
881 	netmsg_service_sync();
882 	crit_enter();
883 	lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg);
884 	crit_exit();
885 	lwkt_replymsg(&nmsg->lmsg, error);
886 	ip_fw_basic_loaded=0;
887 }
888 
889 static int
890 ipfw_basic_stop(void)
891 {
892 	int cpu,i;
893 	struct ipfw_state_context *state_ctx;
894 	struct ip_fw_state *state,*the_state;
895 	struct ipfw_context *ctx;
896 	if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) {
897 		ipfw_basic_flush_state_prt = NULL;
898 		ipfw_basic_append_state_prt = NULL;
899 
900 		for (cpu = 0; cpu < ncpus; cpu++) {
901 			ctx = ipfw_ctx[cpu];
902 			if (ctx != NULL) {
903 				for (i = 0; i < state_hash_size; i++) {
904 					state_ctx = &ctx->state_ctx[i];
905 					if (state_ctx != NULL) {
906 						state = state_ctx->state;
907 						while (state != NULL) {
908 							the_state = state;
909 							state = state->next;
910 							if (the_state ==
911 								state_ctx->last)
912 							state_ctx->last = NULL;
913 
914 							kfree(the_state,
915 								M_IPFW3_BASIC);
916 						}
917 					}
918 				}
919 				ctx->state_hash_size = 0;
920 				kfree(ctx->state_ctx, M_IPFW3_BASIC);
921 				ctx->state_ctx = NULL;
922 			}
923 		}
924 		struct netmsg_base smsg;
925 		netmsg_init(&smsg, NULL, &curthread->td_msgport,
926 				0, ipfw_basic_stop_dispatch);
927 		return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
928 	}
929 	return 1;
930 }
931 
932 
933 static int
934 ipfw3_basic_modevent(module_t mod, int type, void *data)
935 {
936 	int err;
937 	switch (type) {
938 		case MOD_LOAD:
939 			err = ipfw_basic_init();
940 			break;
941 		case MOD_UNLOAD:
942 			err = ipfw_basic_stop();
943 			break;
944 		default:
945 			err = 1;
946 	}
947 	return err;
948 }
949 
950 static moduledata_t ipfw3_basic_mod = {
951 	"ipfw3_basic",
952 	ipfw3_basic_modevent,
953 	NULL
954 };
955 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
956 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1);
957 MODULE_VERSION(ipfw3_basic, 1);
958