16a03354eSMatthew Dillon /*
26a03354eSMatthew Dillon  * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
36a03354eSMatthew Dillon  *
46a03354eSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
56a03354eSMatthew Dillon  * by Bill Yuan <bycn82@gmail.com>
66a03354eSMatthew Dillon  *
76a03354eSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
86a03354eSMatthew Dillon  * modification, are permitted provided that the following conditions
96a03354eSMatthew Dillon  * are met:
106a03354eSMatthew Dillon  *
116a03354eSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
126a03354eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
136a03354eSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
146a03354eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
156a03354eSMatthew Dillon  *    the documentation and/or other materials provided with the
166a03354eSMatthew Dillon  *    distribution.
176a03354eSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
186a03354eSMatthew Dillon  *    contributors may be used to endorse or promote products derived
196a03354eSMatthew Dillon  *    from this software without specific, prior written permission.
206a03354eSMatthew Dillon  *
216a03354eSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
226a03354eSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
236a03354eSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
246a03354eSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
256a03354eSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
266a03354eSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
276a03354eSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
286a03354eSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
296a03354eSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
306a03354eSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
316a03354eSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
326a03354eSMatthew Dillon  * SUCH DAMAGE.
336a03354eSMatthew Dillon  */
346a03354eSMatthew Dillon 
356a03354eSMatthew Dillon #include <sys/param.h>
366a03354eSMatthew Dillon #include <sys/kernel.h>
376a03354eSMatthew Dillon #include <sys/malloc.h>
386a03354eSMatthew Dillon #include <sys/mbuf.h>
396a03354eSMatthew Dillon #include <sys/socketvar.h>
406a03354eSMatthew Dillon #include <sys/sysctl.h>
416a03354eSMatthew Dillon #include <sys/syslog.h>
426a03354eSMatthew Dillon #include <sys/systimer.h>
436a03354eSMatthew Dillon #include <sys/thread2.h>
446a03354eSMatthew Dillon #include <sys/in_cksum.h>
456a03354eSMatthew Dillon 
466a03354eSMatthew Dillon #include <net/if.h>
476a03354eSMatthew Dillon #include <net/ethernet.h>
486a03354eSMatthew Dillon #include <net/netmsg2.h>
496a03354eSMatthew Dillon #include <net/netisr2.h>
506a03354eSMatthew Dillon #include <net/route.h>
516a03354eSMatthew Dillon 
526a03354eSMatthew Dillon #include <netinet/ip.h>
536a03354eSMatthew Dillon #include <netinet/in.h>
546a03354eSMatthew Dillon #include <netinet/in_systm.h>
556a03354eSMatthew Dillon #include <netinet/in_var.h>
566a03354eSMatthew Dillon #include <netinet/in_pcb.h>
576a03354eSMatthew Dillon #include <netinet/ip_var.h>
586a03354eSMatthew Dillon #include <netinet/ip_icmp.h>
596a03354eSMatthew Dillon #include <netinet/tcp.h>
606a03354eSMatthew Dillon #include <netinet/tcp_timer.h>
616a03354eSMatthew Dillon #include <netinet/tcp_var.h>
626a03354eSMatthew Dillon #include <netinet/tcpip.h>
636a03354eSMatthew Dillon #include <netinet/udp.h>
646a03354eSMatthew Dillon #include <netinet/udp_var.h>
656a03354eSMatthew Dillon #include <netinet/ip_divert.h>
666a03354eSMatthew Dillon #include <netinet/if_ether.h>
676a03354eSMatthew Dillon 
686a03354eSMatthew Dillon #include <net/ipfw3/ip_fw.h>
695284582fSBill Yuan #include <net/ipfw3/ip_fw3_table.h>
706a03354eSMatthew Dillon 
716a03354eSMatthew Dillon #include "ip_fw3_basic.h"
726a03354eSMatthew Dillon 
736a03354eSMatthew Dillon #define TIME_LEQ(a, b)	((int)((a) - (b)) <= 0)
746a03354eSMatthew Dillon 
756a03354eSMatthew Dillon extern struct ipfw_context	*ipfw_ctx[MAXCPU];
766a03354eSMatthew Dillon extern int fw_verbose;
776a03354eSMatthew Dillon extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt;
786a03354eSMatthew Dillon extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt;
796a03354eSMatthew Dillon 
806a03354eSMatthew Dillon static int ip_fw_basic_loaded;
816a03354eSMatthew Dillon static struct netmsg_base ipfw_timeout_netmsg;	/* schedule ipfw timeout */
826a03354eSMatthew Dillon static struct callout ipfw_tick_callout;
836a03354eSMatthew Dillon static int state_lifetime = 20;
846a03354eSMatthew Dillon static int state_expiry_check_interval = 10;
856a03354eSMatthew Dillon static int state_count_max = 4096;
866a03354eSMatthew Dillon static int state_hash_size_old = 0;
876a03354eSMatthew Dillon static int state_hash_size = 4096;
886a03354eSMatthew Dillon 
896a03354eSMatthew Dillon 
906a03354eSMatthew Dillon static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS);
916a03354eSMatthew Dillon void adjust_hash_size_dispatch(netmsg_t nmsg);
926a03354eSMatthew Dillon 
936a03354eSMatthew Dillon SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic,
946a03354eSMatthew Dillon 		CTLFLAG_RW, 0, "Firewall Basic");
956a03354eSMatthew Dillon SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size,
966a03354eSMatthew Dillon 		CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0,
976a03354eSMatthew Dillon 		ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size");
986a03354eSMatthew Dillon 
996a03354eSMatthew Dillon SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW,
1006a03354eSMatthew Dillon 		&state_lifetime, 0, "default life time");
1016a03354eSMatthew Dillon SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO,
1026a03354eSMatthew Dillon 		state_expiry_check_interval, CTLFLAG_RW,
1036a03354eSMatthew Dillon 		&state_expiry_check_interval, 0,
1046a03354eSMatthew Dillon 		"default state expiry check interval");
1056a03354eSMatthew Dillon SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW,
1066a03354eSMatthew Dillon 		&state_count_max, 0, "maximum of state");
1076a03354eSMatthew Dillon 
1086a03354eSMatthew Dillon static int
1096a03354eSMatthew Dillon ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS)
1106a03354eSMatthew Dillon {
1116a03354eSMatthew Dillon 	int error, value = 0;
1126a03354eSMatthew Dillon 
1136a03354eSMatthew Dillon 	state_hash_size_old = state_hash_size;
1146a03354eSMatthew Dillon 	value = state_hash_size;
1156a03354eSMatthew Dillon 	error = sysctl_handle_int(oidp, &value, 0, req);
1166a03354eSMatthew Dillon 	if (error || !req->newptr) {
1176a03354eSMatthew Dillon 		goto back;
1186a03354eSMatthew Dillon 	}
1196a03354eSMatthew Dillon 	/*
1206a03354eSMatthew Dillon 	 * Make sure we have a power of 2 and
1216a03354eSMatthew Dillon 	 * do not allow more than 64k entries.
1226a03354eSMatthew Dillon 	 */
1236a03354eSMatthew Dillon 	error = EINVAL;
1246a03354eSMatthew Dillon 	if (value <= 1 || value > 65536) {
1256a03354eSMatthew Dillon 		goto back;
1266a03354eSMatthew Dillon 	}
1276a03354eSMatthew Dillon 	if ((value & (value - 1)) != 0) {
1286a03354eSMatthew Dillon 		goto back;
1296a03354eSMatthew Dillon 	}
1306a03354eSMatthew Dillon 
1316a03354eSMatthew Dillon 	error = 0;
1326a03354eSMatthew Dillon 	if (state_hash_size != value) {
1336a03354eSMatthew Dillon 		state_hash_size = value;
1346a03354eSMatthew Dillon 
1356a03354eSMatthew Dillon 		struct netmsg_base *msg, the_msg;
1366a03354eSMatthew Dillon 		msg = &the_msg;
1376a03354eSMatthew Dillon 		bzero(msg,sizeof(struct netmsg_base));
1386a03354eSMatthew Dillon 
1396a03354eSMatthew Dillon 		netmsg_init(msg, NULL, &curthread->td_msgport,
1406a03354eSMatthew Dillon 				0, adjust_hash_size_dispatch);
1416a03354eSMatthew Dillon 		ifnet_domsg(&msg->lmsg, 0);
1426a03354eSMatthew Dillon 	}
1436a03354eSMatthew Dillon back:
1446a03354eSMatthew Dillon 	return error;
1456a03354eSMatthew Dillon }
1466a03354eSMatthew Dillon 
1476a03354eSMatthew Dillon void
1486a03354eSMatthew Dillon adjust_hash_size_dispatch(netmsg_t nmsg)
1496a03354eSMatthew Dillon {
1506a03354eSMatthew Dillon 	struct ipfw_state_context *state_ctx;
1516a03354eSMatthew Dillon 	struct ip_fw_state *the_state, *state;
1526a03354eSMatthew Dillon 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
1536a03354eSMatthew Dillon 	int i;
1546a03354eSMatthew Dillon 
1556a03354eSMatthew Dillon 	for (i = 0; i < state_hash_size_old; i++) {
1566a03354eSMatthew Dillon 		state_ctx = &ctx->state_ctx[i];
1576a03354eSMatthew Dillon 		if (state_ctx != NULL) {
1586a03354eSMatthew Dillon 			state = state_ctx->state;
1596a03354eSMatthew Dillon 			while (state != NULL) {
1606a03354eSMatthew Dillon 				the_state = state;
1616a03354eSMatthew Dillon 				state = state->next;
1626a03354eSMatthew Dillon 				kfree(the_state, M_IPFW3_BASIC);
1636a03354eSMatthew Dillon 				the_state = NULL;
1646a03354eSMatthew Dillon 			}
1656a03354eSMatthew Dillon 		}
1666a03354eSMatthew Dillon 	}
1676a03354eSMatthew Dillon 	kfree(ctx->state_ctx,M_IPFW3_BASIC);
1686a03354eSMatthew Dillon 	ctx->state_ctx = kmalloc(state_hash_size *
1696a03354eSMatthew Dillon 				sizeof(struct ipfw_state_context),
1706a03354eSMatthew Dillon 				M_IPFW3_BASIC, M_WAITOK | M_ZERO);
1716a03354eSMatthew Dillon 	ctx->state_hash_size = state_hash_size;
1726a03354eSMatthew Dillon 	ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
1736a03354eSMatthew Dillon }
1746a03354eSMatthew Dillon 
1756a03354eSMatthew Dillon 
1766a03354eSMatthew Dillon /*	prototype of the checker functions	*/
1776a03354eSMatthew Dillon void check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1786a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1796a03354eSMatthew Dillon void check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1806a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1816a03354eSMatthew Dillon void check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1826a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1836a03354eSMatthew Dillon void check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1846a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1856a03354eSMatthew Dillon 
1866a03354eSMatthew Dillon void check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1876a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1886a03354eSMatthew Dillon void check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1896a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1906a03354eSMatthew Dillon void check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1916a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1926a03354eSMatthew Dillon void check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1936a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1946a03354eSMatthew Dillon void check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1956a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1966a03354eSMatthew Dillon void check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1976a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
1985284582fSBill Yuan void check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
1995284582fSBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
20063317b93SBill Yuan void check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
20163317b93SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
20263317b93SBill Yuan void check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
20363317b93SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
2046a03354eSMatthew Dillon void check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
2056a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
2065284582fSBill Yuan void check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
2075284582fSBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
20863317b93SBill Yuan void check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
20963317b93SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
21063317b93SBill Yuan void check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
21163317b93SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
2126a03354eSMatthew Dillon void check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
2136a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
2146a03354eSMatthew Dillon void check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
2156a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
2166a03354eSMatthew Dillon void check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
2176a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
2186a03354eSMatthew Dillon void check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
2196a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
220*c1bde762SBill Yuan void check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
221*c1bde762SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
222*c1bde762SBill Yuan void check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
223*c1bde762SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
224*c1bde762SBill Yuan void check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
225*c1bde762SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
226*c1bde762SBill Yuan void check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
227*c1bde762SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
2286a03354eSMatthew Dillon 
2296a03354eSMatthew Dillon /*	prototype of the utility functions	*/
2306a03354eSMatthew Dillon static struct ip_fw *lookup_next_rule(struct ip_fw *me);
2316a03354eSMatthew Dillon static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd);
2326a03354eSMatthew Dillon static __inline int hash_packet(struct ipfw_flow_id *id);
2336a03354eSMatthew Dillon 
2346a03354eSMatthew Dillon static __inline int
2356a03354eSMatthew Dillon hash_packet(struct ipfw_flow_id *id)
2366a03354eSMatthew Dillon {
2376a03354eSMatthew Dillon 	uint32_t i;
2386a03354eSMatthew Dillon 	i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^
2396a03354eSMatthew Dillon 		(id->dst_port) ^ (id->src_port);
2406a03354eSMatthew Dillon 	i &= state_hash_size - 1;
2416a03354eSMatthew Dillon 	return i;
2426a03354eSMatthew Dillon }
2436a03354eSMatthew Dillon 
2446a03354eSMatthew Dillon static struct ip_fw *
2456a03354eSMatthew Dillon lookup_next_rule(struct ip_fw *me)
2466a03354eSMatthew Dillon {
2476a03354eSMatthew Dillon 	struct ip_fw *rule = NULL;
2486a03354eSMatthew Dillon 	ipfw_insn *cmd;
2496a03354eSMatthew Dillon 
2506a03354eSMatthew Dillon 	/* look for action, in case it is a skipto */
2516a03354eSMatthew Dillon 	cmd = ACTION_PTR(me);
2526a03354eSMatthew Dillon 	if ((int)cmd->module == MODULE_BASIC_ID &&
2536a03354eSMatthew Dillon 		(int)cmd->opcode == O_BASIC_SKIPTO) {
2546a03354eSMatthew Dillon 		for (rule = me->next; rule; rule = rule->next) {
2556a03354eSMatthew Dillon 			if (rule->rulenum >= cmd->arg1)
2566a03354eSMatthew Dillon 				break;
2576a03354eSMatthew Dillon 		}
2586a03354eSMatthew Dillon 	}
2596a03354eSMatthew Dillon 	if (rule == NULL) /* failure or not a skipto */
2606a03354eSMatthew Dillon 		rule = me->next;
2616a03354eSMatthew Dillon 
2626a03354eSMatthew Dillon 	me->next_rule = rule;
2636a03354eSMatthew Dillon 	return rule;
2646a03354eSMatthew Dillon }
2656a03354eSMatthew Dillon 
2666a03354eSMatthew Dillon /*
2676a03354eSMatthew Dillon  * when all = 1, it will check all the state_ctx
2686a03354eSMatthew Dillon  */
2696a03354eSMatthew Dillon static struct ip_fw_state *
2706a03354eSMatthew Dillon lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all)
2716a03354eSMatthew Dillon {
2726a03354eSMatthew Dillon 	struct ip_fw_state *state = NULL;
2736a03354eSMatthew Dillon 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
2746a03354eSMatthew Dillon 	struct ipfw_state_context *state_ctx;
2756a03354eSMatthew Dillon 	int start, end, i, count = 0;
2766a03354eSMatthew Dillon 
2776a03354eSMatthew Dillon 	if (all && cmd->arg1) {
2786a03354eSMatthew Dillon 		start = 0;
2796a03354eSMatthew Dillon 		end = state_hash_size - 1;
2806a03354eSMatthew Dillon 	} else {
2816a03354eSMatthew Dillon 		start = hash_packet(&args->f_id);
2826a03354eSMatthew Dillon 		end = hash_packet(&args->f_id);
2836a03354eSMatthew Dillon 	}
2846a03354eSMatthew Dillon 	for (i = start; i <= end; i++) {
2856a03354eSMatthew Dillon 		state_ctx = &ctx->state_ctx[i];
2866a03354eSMatthew Dillon 		if (state_ctx != NULL) {
2876a03354eSMatthew Dillon 			state = state_ctx->state;
2886a03354eSMatthew Dillon 			struct ipfw_flow_id	*fid = &args->f_id;
2896a03354eSMatthew Dillon 			while (state != NULL) {
2906a03354eSMatthew Dillon 				if (cmd->arg1) {
2916a03354eSMatthew Dillon 					if ((cmd->arg3 == 1 &&
2926a03354eSMatthew Dillon 						fid->src_ip ==
2936a03354eSMatthew Dillon 						state->flow_id.src_ip) ||
2946a03354eSMatthew Dillon 						(cmd->arg3 == 2 &&
2956a03354eSMatthew Dillon 						fid->src_port ==
2966a03354eSMatthew Dillon 						state->flow_id.src_port) ||
2976a03354eSMatthew Dillon 						(cmd->arg3 == 3 &&
2986a03354eSMatthew Dillon 						fid->dst_ip ==
2996a03354eSMatthew Dillon 						state->flow_id.dst_ip) ||
3006a03354eSMatthew Dillon 						(cmd->arg3 == 4 &&
3016a03354eSMatthew Dillon 						fid->dst_port ==
3026a03354eSMatthew Dillon 						state->flow_id.dst_port)) {
3036a03354eSMatthew Dillon 
3046a03354eSMatthew Dillon 						count++;
3056a03354eSMatthew Dillon 						if (count >= cmd->arg1) {
3066a03354eSMatthew Dillon 							*limited = 1;
3076a03354eSMatthew Dillon 							goto done;
3086a03354eSMatthew Dillon 						}
3096a03354eSMatthew Dillon 					}
3106a03354eSMatthew Dillon 				}
3116a03354eSMatthew Dillon 
3126a03354eSMatthew Dillon 				if (fid->proto == state->flow_id.proto) {
3136a03354eSMatthew Dillon 					if (fid->src_ip ==
3146a03354eSMatthew Dillon 					state->flow_id.src_ip &&
3156a03354eSMatthew Dillon 					fid->dst_ip ==
3166a03354eSMatthew Dillon 					state->flow_id.dst_ip &&
3176a03354eSMatthew Dillon 					(fid->src_port ==
3186a03354eSMatthew Dillon 					state->flow_id.src_port ||
3196a03354eSMatthew Dillon 					state->flow_id.src_port == 0) &&
3206a03354eSMatthew Dillon 					(fid->dst_port ==
3216a03354eSMatthew Dillon 					state->flow_id.dst_port ||
3226a03354eSMatthew Dillon 					state->flow_id.dst_port == 0)) {
3236a03354eSMatthew Dillon 						goto done;
3246a03354eSMatthew Dillon 					}
3256a03354eSMatthew Dillon 					if (fid->src_ip ==
3266a03354eSMatthew Dillon 					state->flow_id.dst_ip &&
3276a03354eSMatthew Dillon 					fid->dst_ip ==
3286a03354eSMatthew Dillon 					state->flow_id.src_ip &&
3296a03354eSMatthew Dillon 					(fid->src_port ==
3306a03354eSMatthew Dillon 					state->flow_id.dst_port ||
3316a03354eSMatthew Dillon 					state->flow_id.dst_port == 0) &&
3326a03354eSMatthew Dillon 					(fid->dst_port ==
3336a03354eSMatthew Dillon 					state->flow_id.src_port ||
3346a03354eSMatthew Dillon 					state->flow_id.src_port == 0)) {
3356a03354eSMatthew Dillon 						goto done;
3366a03354eSMatthew Dillon 					}
3376a03354eSMatthew Dillon 				}
3386a03354eSMatthew Dillon 				state = state->next;
3396a03354eSMatthew Dillon 			}
3406a03354eSMatthew Dillon 		}
3416a03354eSMatthew Dillon 	}
3426a03354eSMatthew Dillon done:
3436a03354eSMatthew Dillon 	return state;
3446a03354eSMatthew Dillon }
3456a03354eSMatthew Dillon 
3466a03354eSMatthew Dillon static struct ip_fw_state *
3476a03354eSMatthew Dillon install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args)
3486a03354eSMatthew Dillon {
3496a03354eSMatthew Dillon 	struct ip_fw_state *state;
3506a03354eSMatthew Dillon 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
3516a03354eSMatthew Dillon 	struct ipfw_state_context *state_ctx;
3526a03354eSMatthew Dillon 	state_ctx = &ctx->state_ctx[hash_packet(&args->f_id)];
3536a03354eSMatthew Dillon 	state = kmalloc(sizeof(struct ip_fw_state),
3546a03354eSMatthew Dillon 			M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
3556a03354eSMatthew Dillon 	if (state == NULL) {
3566a03354eSMatthew Dillon 		return NULL;
3576a03354eSMatthew Dillon 	}
3586a03354eSMatthew Dillon 	state->stub = rule;
3596a03354eSMatthew Dillon 	state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ;
3606a03354eSMatthew Dillon 	state->timestamp = time_second;
3616a03354eSMatthew Dillon 	state->expiry = 0;
3626a03354eSMatthew Dillon 	bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id));
3636a03354eSMatthew Dillon 	//append the state into the state chian
3646a03354eSMatthew Dillon 	if (state_ctx->last != NULL)
3656a03354eSMatthew Dillon 		state_ctx->last->next = state;
3666a03354eSMatthew Dillon 	else
3676a03354eSMatthew Dillon 		state_ctx->state = state;
3686a03354eSMatthew Dillon 	state_ctx->last = state;
3696a03354eSMatthew Dillon 	state_ctx->count++;
3706a03354eSMatthew Dillon 	return state;
3716a03354eSMatthew Dillon }
3726a03354eSMatthew Dillon 
3736a03354eSMatthew Dillon 
3746a03354eSMatthew Dillon static int
3756a03354eSMatthew Dillon iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
3766a03354eSMatthew Dillon {
3776a03354eSMatthew Dillon 	if (ifp == NULL)	/* no iface with this packet, match fails */
3786a03354eSMatthew Dillon 		return 0;
3796a03354eSMatthew Dillon 
3806a03354eSMatthew Dillon 	/* Check by name or by IP address */
3816a03354eSMatthew Dillon 	if (cmd->name[0] != '\0') { /* match by name */
3826a03354eSMatthew Dillon 		/* Check name */
3836a03354eSMatthew Dillon 		if (cmd->p.glob) {
3846a03354eSMatthew Dillon 			if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
3856a03354eSMatthew Dillon 				return(1);
3866a03354eSMatthew Dillon 		} else {
3876a03354eSMatthew Dillon 			if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
3886a03354eSMatthew Dillon 				return(1);
3896a03354eSMatthew Dillon 		}
3906a03354eSMatthew Dillon 	} else {
3916a03354eSMatthew Dillon 		struct ifaddr_container *ifac;
3926a03354eSMatthew Dillon 
3936a03354eSMatthew Dillon 		TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
3946a03354eSMatthew Dillon 			struct ifaddr *ia = ifac->ifa;
3956a03354eSMatthew Dillon 
3966a03354eSMatthew Dillon 			if (ia->ifa_addr == NULL)
3976a03354eSMatthew Dillon 				continue;
3986a03354eSMatthew Dillon 			if (ia->ifa_addr->sa_family != AF_INET)
3996a03354eSMatthew Dillon 				continue;
4006a03354eSMatthew Dillon 			if (cmd->p.ip.s_addr ==
4016a03354eSMatthew Dillon 				((struct sockaddr_in *)
4026a03354eSMatthew Dillon 				(ia->ifa_addr))->sin_addr.s_addr)
4036a03354eSMatthew Dillon 					return(1);	/* match */
4046a03354eSMatthew Dillon 
4056a03354eSMatthew Dillon 		}
4066a03354eSMatthew Dillon 	}
4076a03354eSMatthew Dillon 	return 0;	/* no match, fail ... */
4086a03354eSMatthew Dillon }
4096a03354eSMatthew Dillon 
4106a03354eSMatthew Dillon /* implimentation of the checker functions */
4116a03354eSMatthew Dillon void
4126a03354eSMatthew Dillon check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
4136a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
4146a03354eSMatthew Dillon {
4156a03354eSMatthew Dillon 	(*f)->pcnt++;
4166a03354eSMatthew Dillon 	(*f)->bcnt += ip_len;
4176a03354eSMatthew Dillon 	(*f)->timestamp = time_second;
4186a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NEXT;
4196a03354eSMatthew Dillon }
4206a03354eSMatthew Dillon 
4216a03354eSMatthew Dillon void
4226a03354eSMatthew Dillon check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
4236a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
4246a03354eSMatthew Dillon {
4256a03354eSMatthew Dillon 	(*f)->pcnt++;
4266a03354eSMatthew Dillon 	(*f)->bcnt += ip_len;
4276a03354eSMatthew Dillon 	(*f)->timestamp = time_second;
4286a03354eSMatthew Dillon 	if ((*f)->next_rule == NULL)
4296a03354eSMatthew Dillon 		lookup_next_rule(*f);
4306a03354eSMatthew Dillon 
4316a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_AGAIN;
4326a03354eSMatthew Dillon }
4336a03354eSMatthew Dillon 
4346a03354eSMatthew Dillon void
4356a03354eSMatthew Dillon check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
4366a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
4376a03354eSMatthew Dillon {
4386a03354eSMatthew Dillon 	struct sockaddr_in *sin, *sa;
4396a03354eSMatthew Dillon 	struct m_tag *mtag;
4406a03354eSMatthew Dillon 
4416a03354eSMatthew Dillon 	if ((*args)->eh) {	/* not valid on layer2 pkts */
4426a03354eSMatthew Dillon 		*cmd_ctl=IP_FW_CTL_NEXT;
4436a03354eSMatthew Dillon 		return;
4446a03354eSMatthew Dillon 	}
4456a03354eSMatthew Dillon 
4466a03354eSMatthew Dillon 	(*f)->pcnt++;
4476a03354eSMatthew Dillon 	(*f)->bcnt += ip_len;
4486a03354eSMatthew Dillon 	(*f)->timestamp = time_second;
4496a03354eSMatthew Dillon 	if ((*f)->next_rule == NULL)
4506a03354eSMatthew Dillon 		lookup_next_rule(*f);
4516a03354eSMatthew Dillon 
4526a03354eSMatthew Dillon 	mtag = m_tag_get(PACKET_TAG_IPFORWARD,
4536a03354eSMatthew Dillon 			sizeof(*sin), M_NOWAIT);
4546a03354eSMatthew Dillon 	if (mtag == NULL) {
4556a03354eSMatthew Dillon 		*cmd_val = IP_FW_DENY;
4566a03354eSMatthew Dillon 		*cmd_ctl = IP_FW_CTL_DONE;
4576a03354eSMatthew Dillon 		return;
4586a03354eSMatthew Dillon 	}
4596a03354eSMatthew Dillon 	sin = m_tag_data(mtag);
4606a03354eSMatthew Dillon 	sa = &((ipfw_insn_sa *)cmd)->sa;
4616a03354eSMatthew Dillon 	/* arg3: count of the dest, arg1: type of fwd */
4626a03354eSMatthew Dillon 	int i = 0;
4636a03354eSMatthew Dillon 	if(cmd->arg3 > 1) {
4646a03354eSMatthew Dillon 		if (cmd->arg1 == 0) {		/* type: random */
4656a03354eSMatthew Dillon 			i = krandom() % cmd->arg3;
4666a03354eSMatthew Dillon 		} else if (cmd->arg1 == 1) {	/* type: round-robin */
4676a03354eSMatthew Dillon 			i = cmd->arg2++ % cmd->arg3;
4686a03354eSMatthew Dillon 		} else if (cmd->arg1 == 2) {	/* type: sticky */
4696a03354eSMatthew Dillon 			struct ip *ip = mtod((*args)->m, struct ip *);
4706a03354eSMatthew Dillon 			i = ip->ip_src.s_addr & (cmd->arg3 - 1);
4716a03354eSMatthew Dillon 		}
4726a03354eSMatthew Dillon 		sa += i;
4736a03354eSMatthew Dillon 	}
4746a03354eSMatthew Dillon 	*sin = *sa;	/* apply the destination */
4756a03354eSMatthew Dillon 	m_tag_prepend((*args)->m, mtag);
4766a03354eSMatthew Dillon 	(*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED;
4776a03354eSMatthew Dillon 	(*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
4786a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_DONE;
4796a03354eSMatthew Dillon 	*cmd_val = IP_FW_PASS;
4806a03354eSMatthew Dillon }
4816a03354eSMatthew Dillon 
4826a03354eSMatthew Dillon void
4836a03354eSMatthew Dillon check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
4846a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
4856a03354eSMatthew Dillon {
4866a03354eSMatthew Dillon 	struct ip_fw_state *state=NULL;
4876a03354eSMatthew Dillon 	int limited = 0 ;
4886a03354eSMatthew Dillon 	state = lookup_state(*args, cmd, &limited, 0);
4896a03354eSMatthew Dillon 	if (state != NULL) {
4906a03354eSMatthew Dillon 		state->pcnt++;
4916a03354eSMatthew Dillon 		state->bcnt += ip_len;
4926a03354eSMatthew Dillon 		state->timestamp = time_second;
4936a03354eSMatthew Dillon 		(*f)->pcnt++;
4946a03354eSMatthew Dillon 		(*f)->bcnt += ip_len;
4956a03354eSMatthew Dillon 		(*f)->timestamp = time_second;
4966a03354eSMatthew Dillon 		*f = state->stub;
4976a03354eSMatthew Dillon 		*cmd_ctl = IP_FW_CTL_CHK_STATE;
4986a03354eSMatthew Dillon 	} else {
4996a03354eSMatthew Dillon 		*cmd_ctl = IP_FW_CTL_NEXT;
5006a03354eSMatthew Dillon 	}
5016a03354eSMatthew Dillon }
5026a03354eSMatthew Dillon 
5036a03354eSMatthew Dillon void
5046a03354eSMatthew Dillon check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
5056a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
5066a03354eSMatthew Dillon {
5076a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
5086a03354eSMatthew Dillon 	*cmd_val = ((*args)->oif == NULL);
5096a03354eSMatthew Dillon }
5106a03354eSMatthew Dillon 
5116a03354eSMatthew Dillon void
5126a03354eSMatthew Dillon check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
5136a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
5146a03354eSMatthew Dillon {
5156a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
5166a03354eSMatthew Dillon 	*cmd_val = ((*args)->oif != NULL);
5176a03354eSMatthew Dillon }
5186a03354eSMatthew Dillon 
5196a03354eSMatthew Dillon void
5206a03354eSMatthew Dillon check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
5216a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
5226a03354eSMatthew Dillon {
5236a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
5246a03354eSMatthew Dillon 	*cmd_val = iface_match((*args)->oif ?
5256a03354eSMatthew Dillon 			(*args)->oif : (*args)->m->m_pkthdr.rcvif,
5266a03354eSMatthew Dillon 			(ipfw_insn_if *)cmd);
5276a03354eSMatthew Dillon }
5286a03354eSMatthew Dillon 
5296a03354eSMatthew Dillon void
5306a03354eSMatthew Dillon check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
5316a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
5326a03354eSMatthew Dillon {
5336a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
5346a03354eSMatthew Dillon 	*cmd_val = ((*args)->f_id.proto == cmd->arg1);
5356a03354eSMatthew Dillon }
5366a03354eSMatthew Dillon 
5376a03354eSMatthew Dillon void
5386a03354eSMatthew Dillon check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
5396a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
5406a03354eSMatthew Dillon {
5416a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
5426a03354eSMatthew Dillon 	*cmd_val = (krandom() % 100) < cmd->arg1;
5436a03354eSMatthew Dillon }
5446a03354eSMatthew Dillon 
5456a03354eSMatthew Dillon void
5466a03354eSMatthew Dillon check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
5476a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
5486a03354eSMatthew Dillon {
5496a03354eSMatthew Dillon 	struct in_addr src_ip;
5506a03354eSMatthew Dillon 	u_int hlen = 0;
5516a03354eSMatthew Dillon 	struct mbuf *m = (*args)->m;
5526a03354eSMatthew Dillon 	struct ip *ip = mtod(m, struct ip *);
5536a03354eSMatthew Dillon 	src_ip = ip->ip_src;
5546a03354eSMatthew Dillon 	if ((*args)->eh == NULL ||
5556a03354eSMatthew Dillon 		(m->m_pkthdr.len >= sizeof(struct ip) &&
5566a03354eSMatthew Dillon 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
5576a03354eSMatthew Dillon 		hlen = ip->ip_hl << 2;
5586a03354eSMatthew Dillon 	}
5596a03354eSMatthew Dillon 	*cmd_val = (hlen > 0 &&
5606a03354eSMatthew Dillon 			((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
5616a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
5626a03354eSMatthew Dillon }
5636a03354eSMatthew Dillon 
5646a03354eSMatthew Dillon void
5655284582fSBill Yuan check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
5665284582fSBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
5675284582fSBill Yuan {
5685284582fSBill Yuan 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
5695284582fSBill Yuan 	struct ipfw_table_context *table_ctx;
5705284582fSBill Yuan 	struct radix_node_head *rnh;
5715284582fSBill Yuan 	struct sockaddr_in sa;
5725284582fSBill Yuan 
5735284582fSBill Yuan 	struct mbuf *m = (*args)->m;
5745284582fSBill Yuan 	struct ip *ip = mtod(m, struct ip *);
5755284582fSBill Yuan 	struct in_addr src_ip = ip->ip_src;
5765284582fSBill Yuan 
5775284582fSBill Yuan 	*cmd_val = IP_FW_NOT_MATCH;
5785284582fSBill Yuan 
5795284582fSBill Yuan 	table_ctx = ctx->table_ctx;
5805284582fSBill Yuan 	table_ctx += cmd->arg1;
5815284582fSBill Yuan 
5825284582fSBill Yuan         if (table_ctx->type != 0) {
5835284582fSBill Yuan                 rnh = table_ctx->node;
5845284582fSBill Yuan                 sa.sin_len = 8;
5855284582fSBill Yuan                 sa.sin_addr.s_addr = src_ip.s_addr;
5865284582fSBill Yuan                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
5875284582fSBill Yuan                         *cmd_val = IP_FW_MATCH;
5885284582fSBill Yuan         }
5895284582fSBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
5905284582fSBill Yuan }
5915284582fSBill Yuan 
5925284582fSBill Yuan void
59363317b93SBill Yuan check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
59463317b93SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
59563317b93SBill Yuan {
59663317b93SBill Yuan 	struct in_addr src_ip;
59763317b93SBill Yuan 	u_int hlen = 0;
59863317b93SBill Yuan 	struct mbuf *m = (*args)->m;
59963317b93SBill Yuan 	struct ip *ip = mtod(m, struct ip *);
60063317b93SBill Yuan 	src_ip = ip->ip_src;
60163317b93SBill Yuan 	if ((*args)->eh == NULL ||
60263317b93SBill Yuan 		(m->m_pkthdr.len >= sizeof(struct ip) &&
60363317b93SBill Yuan 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
60463317b93SBill Yuan 		hlen = ip->ip_hl << 2;
60563317b93SBill Yuan 	}
60663317b93SBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
60763317b93SBill Yuan 	if (hlen > 0) {
60863317b93SBill Yuan 		struct ifnet *tif;
60963317b93SBill Yuan 		tif = INADDR_TO_IFP(&src_ip);
61063317b93SBill Yuan 		*cmd_val = (tif != NULL);
61163317b93SBill Yuan 	} else {
61263317b93SBill Yuan 		*cmd_val = IP_FW_NOT_MATCH;
61363317b93SBill Yuan 	}
61463317b93SBill Yuan }
61563317b93SBill Yuan 
61663317b93SBill Yuan void
61763317b93SBill Yuan check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
61863317b93SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
61963317b93SBill Yuan {
62063317b93SBill Yuan 	struct in_addr src_ip;
62163317b93SBill Yuan 	u_int hlen = 0;
62263317b93SBill Yuan 	struct mbuf *m = (*args)->m;
62363317b93SBill Yuan 	struct ip *ip = mtod(m, struct ip *);
62463317b93SBill Yuan 	src_ip = ip->ip_src;
62563317b93SBill Yuan 	if ((*args)->eh == NULL ||
62663317b93SBill Yuan 		(m->m_pkthdr.len >= sizeof(struct ip) &&
62763317b93SBill Yuan 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
62863317b93SBill Yuan 		hlen = ip->ip_hl << 2;
62963317b93SBill Yuan 	}
63063317b93SBill Yuan 
63163317b93SBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
63263317b93SBill Yuan 	*cmd_val = (hlen > 0 &&
63363317b93SBill Yuan 			((ipfw_insn_ip *)cmd)->addr.s_addr ==
63463317b93SBill Yuan 			(src_ip.s_addr &
63563317b93SBill Yuan 			((ipfw_insn_ip *)cmd)->mask.s_addr));
63663317b93SBill Yuan }
63763317b93SBill Yuan 
63863317b93SBill Yuan void
6396a03354eSMatthew Dillon check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
6406a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
6416a03354eSMatthew Dillon {
6426a03354eSMatthew Dillon 	struct in_addr dst_ip;
6436a03354eSMatthew Dillon 	u_int hlen = 0;
6446a03354eSMatthew Dillon 	struct mbuf *m = (*args)->m;
6456a03354eSMatthew Dillon 	struct ip *ip = mtod(m, struct ip *);
6466a03354eSMatthew Dillon 	dst_ip = ip->ip_dst;
6476a03354eSMatthew Dillon 	if ((*args)->eh == NULL ||
6486a03354eSMatthew Dillon 		(m->m_pkthdr.len >= sizeof(struct ip) &&
6496a03354eSMatthew Dillon 		 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
6506a03354eSMatthew Dillon 		hlen = ip->ip_hl << 2;
6516a03354eSMatthew Dillon 	}
6526a03354eSMatthew Dillon 	*cmd_val = (hlen > 0 &&
6536a03354eSMatthew Dillon 			((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
6546a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
6556a03354eSMatthew Dillon }
6566a03354eSMatthew Dillon 
6576a03354eSMatthew Dillon void
6585284582fSBill Yuan check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
6595284582fSBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
6605284582fSBill Yuan {
6615284582fSBill Yuan 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
6625284582fSBill Yuan 	struct ipfw_table_context *table_ctx;
6635284582fSBill Yuan 	struct radix_node_head *rnh;
6645284582fSBill Yuan 	struct sockaddr_in sa;
6655284582fSBill Yuan 
6665284582fSBill Yuan 	struct mbuf *m = (*args)->m;
6675284582fSBill Yuan 	struct ip *ip = mtod(m, struct ip *);
6685284582fSBill Yuan 	struct in_addr dst_ip = ip->ip_dst;
6695284582fSBill Yuan 
6705284582fSBill Yuan 	*cmd_val = IP_FW_NOT_MATCH;
6715284582fSBill Yuan 
6725284582fSBill Yuan 	table_ctx = ctx->table_ctx;
6735284582fSBill Yuan 	table_ctx += cmd->arg1;
6745284582fSBill Yuan 
6755284582fSBill Yuan         if (table_ctx->type != 0) {
6765284582fSBill Yuan                 rnh = table_ctx->node;
6775284582fSBill Yuan                 sa.sin_len = 8;
6785284582fSBill Yuan                 sa.sin_addr.s_addr = dst_ip.s_addr;
6795284582fSBill Yuan                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
6805284582fSBill Yuan                         *cmd_val = IP_FW_MATCH;
6815284582fSBill Yuan         }
6825284582fSBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
6835284582fSBill Yuan }
6845284582fSBill Yuan 
6855284582fSBill Yuan void
68663317b93SBill Yuan check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
68763317b93SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
68863317b93SBill Yuan {
68963317b93SBill Yuan 	struct in_addr dst_ip;
69063317b93SBill Yuan 	u_int hlen = 0;
69163317b93SBill Yuan 	struct mbuf *m = (*args)->m;
69263317b93SBill Yuan 	struct ip *ip = mtod(m, struct ip *);
69363317b93SBill Yuan 	dst_ip = ip->ip_src;
69463317b93SBill Yuan 	if ((*args)->eh == NULL ||
69563317b93SBill Yuan 		(m->m_pkthdr.len >= sizeof(struct ip) &&
69663317b93SBill Yuan 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
69763317b93SBill Yuan 		hlen = ip->ip_hl << 2;
69863317b93SBill Yuan 	}
69963317b93SBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
70063317b93SBill Yuan 	if (hlen > 0) {
70163317b93SBill Yuan 		struct ifnet *tif;
70263317b93SBill Yuan 		tif = INADDR_TO_IFP(&dst_ip);
70363317b93SBill Yuan 		*cmd_val = (tif != NULL);
70463317b93SBill Yuan 	} else {
70563317b93SBill Yuan 		*cmd_val = IP_FW_NOT_MATCH;
70663317b93SBill Yuan 	}
70763317b93SBill Yuan }
70863317b93SBill Yuan 
70963317b93SBill Yuan void
71063317b93SBill Yuan check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
71163317b93SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
71263317b93SBill Yuan {
71363317b93SBill Yuan 	struct in_addr dst_ip;
71463317b93SBill Yuan 	u_int hlen = 0;
71563317b93SBill Yuan 	struct mbuf *m = (*args)->m;
71663317b93SBill Yuan 	struct ip *ip = mtod(m, struct ip *);
71763317b93SBill Yuan 	dst_ip = ip->ip_src;
71863317b93SBill Yuan 	if ((*args)->eh == NULL ||
71963317b93SBill Yuan 		(m->m_pkthdr.len >= sizeof(struct ip) &&
72063317b93SBill Yuan 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
72163317b93SBill Yuan 		hlen = ip->ip_hl << 2;
72263317b93SBill Yuan 	}
72363317b93SBill Yuan 
72463317b93SBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
72563317b93SBill Yuan 	*cmd_val = (hlen > 0 &&
72663317b93SBill Yuan 			((ipfw_insn_ip *)cmd)->addr.s_addr ==
72763317b93SBill Yuan 			(dst_ip.s_addr &
72863317b93SBill Yuan 			((ipfw_insn_ip *)cmd)->mask.s_addr));
72963317b93SBill Yuan }
73063317b93SBill Yuan 
73163317b93SBill Yuan void
7326a03354eSMatthew Dillon check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
7336a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
7346a03354eSMatthew Dillon {
7356a03354eSMatthew Dillon 	struct ip_fw_state *state;
7366a03354eSMatthew Dillon 	int limited = 0;
7376a03354eSMatthew Dillon 
7386a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
7396a03354eSMatthew Dillon 	state = lookup_state(*args, cmd, &limited, 1);
7406a03354eSMatthew Dillon 	if (limited == 1) {
7416a03354eSMatthew Dillon 		*cmd_val = IP_FW_NOT_MATCH;
7426a03354eSMatthew Dillon 	} else {
7436a03354eSMatthew Dillon 		if (state == NULL)
7446a03354eSMatthew Dillon 			state = install_state(*f, cmd, *args);
7456a03354eSMatthew Dillon 
7466a03354eSMatthew Dillon 		if (state != NULL) {
7476a03354eSMatthew Dillon 			state->pcnt++;
7486a03354eSMatthew Dillon 			state->bcnt += ip_len;
7496a03354eSMatthew Dillon 			state->timestamp = time_second;
7506a03354eSMatthew Dillon 			*cmd_val = IP_FW_MATCH;
7516a03354eSMatthew Dillon 		} else {
7526a03354eSMatthew Dillon 			*cmd_val = IP_FW_NOT_MATCH;
7536a03354eSMatthew Dillon 		}
7546a03354eSMatthew Dillon 	}
7556a03354eSMatthew Dillon }
7566a03354eSMatthew Dillon 
7576a03354eSMatthew Dillon void
7586a03354eSMatthew Dillon check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
7596a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
7606a03354eSMatthew Dillon {
7616a03354eSMatthew Dillon 	struct m_tag *mtag = m_tag_locate((*args)->m,
7626a03354eSMatthew Dillon 			MTAG_IPFW, cmd->arg1, NULL);
7636a03354eSMatthew Dillon 	if (mtag == NULL) {
7646a03354eSMatthew Dillon 		mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT);
7656a03354eSMatthew Dillon 		if (mtag != NULL)
7666a03354eSMatthew Dillon 			m_tag_prepend((*args)->m, mtag);
7676a03354eSMatthew Dillon 
7686a03354eSMatthew Dillon 	}
7696a03354eSMatthew Dillon 	(*f)->pcnt++;
7706a03354eSMatthew Dillon 	(*f)->bcnt += ip_len;
7716a03354eSMatthew Dillon 	(*f)->timestamp = time_second;
7726a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NEXT;
7736a03354eSMatthew Dillon }
7746a03354eSMatthew Dillon 
7756a03354eSMatthew Dillon void
7766a03354eSMatthew Dillon check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
7776a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
7786a03354eSMatthew Dillon {
7796a03354eSMatthew Dillon 	struct m_tag *mtag = m_tag_locate((*args)->m,
7806a03354eSMatthew Dillon 			MTAG_IPFW, cmd->arg1, NULL);
7816a03354eSMatthew Dillon 	if (mtag != NULL)
7826a03354eSMatthew Dillon 		m_tag_delete((*args)->m, mtag);
7836a03354eSMatthew Dillon 
7846a03354eSMatthew Dillon 	(*f)->pcnt++;
7856a03354eSMatthew Dillon 	(*f)->bcnt += ip_len;
7866a03354eSMatthew Dillon 	(*f)->timestamp = time_second;
7876a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NEXT;
7886a03354eSMatthew Dillon }
7896a03354eSMatthew Dillon 
7906a03354eSMatthew Dillon void
7916a03354eSMatthew Dillon check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
7926a03354eSMatthew Dillon 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
7936a03354eSMatthew Dillon {
7946a03354eSMatthew Dillon 	*cmd_ctl = IP_FW_CTL_NO;
7956a03354eSMatthew Dillon 	if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL )
7966a03354eSMatthew Dillon 		*cmd_val = IP_FW_MATCH;
7976a03354eSMatthew Dillon 	else
7986a03354eSMatthew Dillon 		*cmd_val = IP_FW_NOT_MATCH;
7996a03354eSMatthew Dillon }
8006a03354eSMatthew Dillon 
801*c1bde762SBill Yuan void
802*c1bde762SBill Yuan check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
803*c1bde762SBill Yuan         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
804*c1bde762SBill Yuan {
805*c1bde762SBill Yuan         *cmd_ctl = IP_FW_CTL_NO;
806*c1bde762SBill Yuan         if ((*args)->f_id.src_port == cmd->arg1)
807*c1bde762SBill Yuan                 *cmd_val = IP_FW_MATCH;
808*c1bde762SBill Yuan         else
809*c1bde762SBill Yuan                 *cmd_val = IP_FW_NOT_MATCH;
810*c1bde762SBill Yuan }
811*c1bde762SBill Yuan 
812*c1bde762SBill Yuan void
813*c1bde762SBill Yuan check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
814*c1bde762SBill Yuan         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
815*c1bde762SBill Yuan {
816*c1bde762SBill Yuan         *cmd_ctl = IP_FW_CTL_NO;
817*c1bde762SBill Yuan         if ((*args)->f_id.dst_port == cmd->arg1)
818*c1bde762SBill Yuan                 *cmd_val = IP_FW_MATCH;
819*c1bde762SBill Yuan         else
820*c1bde762SBill Yuan                 *cmd_val = IP_FW_NOT_MATCH;
821*c1bde762SBill Yuan }
822*c1bde762SBill Yuan 
823*c1bde762SBill Yuan void
824*c1bde762SBill Yuan check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
825*c1bde762SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
826*c1bde762SBill Yuan {
827*c1bde762SBill Yuan 	struct in_addr src_ip;
828*c1bde762SBill Yuan 	u_int hlen = 0;
829*c1bde762SBill Yuan 	struct mbuf *m = (*args)->m;
830*c1bde762SBill Yuan 	struct ip *ip = mtod(m, struct ip *);
831*c1bde762SBill Yuan 	src_ip = ip->ip_src;
832*c1bde762SBill Yuan 	if ((*args)->eh == NULL ||
833*c1bde762SBill Yuan 		(m->m_pkthdr.len >= sizeof(struct ip) &&
834*c1bde762SBill Yuan 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
835*c1bde762SBill Yuan 		hlen = ip->ip_hl << 2;
836*c1bde762SBill Yuan 	}
837*c1bde762SBill Yuan 	*cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
838*c1bde762SBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
839*c1bde762SBill Yuan 	if (*cmd_val && (*args)->f_id.src_port == cmd->arg1)
840*c1bde762SBill Yuan 		*cmd_val = IP_FW_MATCH;
841*c1bde762SBill Yuan 	else
842*c1bde762SBill Yuan 		*cmd_val = IP_FW_NOT_MATCH;
843*c1bde762SBill Yuan }
844*c1bde762SBill Yuan 
845*c1bde762SBill Yuan void
846*c1bde762SBill Yuan check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
847*c1bde762SBill Yuan 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
848*c1bde762SBill Yuan {
849*c1bde762SBill Yuan 	struct in_addr dst_ip;
850*c1bde762SBill Yuan 	u_int hlen = 0;
851*c1bde762SBill Yuan 	struct mbuf *m = (*args)->m;
852*c1bde762SBill Yuan 	struct ip *ip = mtod(m, struct ip *);
853*c1bde762SBill Yuan 	dst_ip = ip->ip_dst;
854*c1bde762SBill Yuan 	if ((*args)->eh == NULL ||
855*c1bde762SBill Yuan 		(m->m_pkthdr.len >= sizeof(struct ip) &&
856*c1bde762SBill Yuan 		 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
857*c1bde762SBill Yuan 		hlen = ip->ip_hl << 2;
858*c1bde762SBill Yuan 	}
859*c1bde762SBill Yuan 	*cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
860*c1bde762SBill Yuan 	*cmd_ctl = IP_FW_CTL_NO;
861*c1bde762SBill Yuan 	if (*cmd_val && (*args)->f_id.dst_port == cmd->arg1)
862*c1bde762SBill Yuan 		*cmd_val = IP_FW_MATCH;
863*c1bde762SBill Yuan 	else
864*c1bde762SBill Yuan 		*cmd_val = IP_FW_NOT_MATCH;
865*c1bde762SBill Yuan }
866*c1bde762SBill Yuan 
867*c1bde762SBill Yuan 
868*c1bde762SBill Yuan 
8696a03354eSMatthew Dillon static void
8706a03354eSMatthew Dillon ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state)
8716a03354eSMatthew Dillon {
8726a03354eSMatthew Dillon 	struct ip_fw_state *state;
8736a03354eSMatthew Dillon 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
8746a03354eSMatthew Dillon 	struct ipfw_state_context *state_ctx;
8756a03354eSMatthew Dillon 	state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))];
8766a03354eSMatthew Dillon 	state = kmalloc(sizeof(struct ip_fw_state),
8776a03354eSMatthew Dillon 			M_IPFW3_BASIC, M_WAITOK | M_ZERO);
8786a03354eSMatthew Dillon 	struct ip_fw *rule = ctx->ipfw_rule_chain;
8796a03354eSMatthew Dillon 	while (rule != NULL) {
8806a03354eSMatthew Dillon 		if (rule->rulenum == ioc_state->rulenum) {
8816a03354eSMatthew Dillon 			break;
8826a03354eSMatthew Dillon 		}
8836a03354eSMatthew Dillon 		rule = rule->next;
8846a03354eSMatthew Dillon 	}
8856a03354eSMatthew Dillon 	if (rule == NULL)
8866a03354eSMatthew Dillon 		return;
8876a03354eSMatthew Dillon 
8886a03354eSMatthew Dillon 	state->stub = rule;
8896a03354eSMatthew Dillon 
8906a03354eSMatthew Dillon 	state->lifetime = ioc_state->lifetime == 0 ?
8916a03354eSMatthew Dillon 		state_lifetime : ioc_state->lifetime ;
8926a03354eSMatthew Dillon 	state->timestamp = time_second;
8936a03354eSMatthew Dillon 	state->expiry = ioc_state->expiry;
8946a03354eSMatthew Dillon 	bcopy(&ioc_state->flow_id, &state->flow_id,
8956a03354eSMatthew Dillon 			sizeof(struct ipfw_flow_id));
8966a03354eSMatthew Dillon 	//append the state into the state chian
8976a03354eSMatthew Dillon 	if (state_ctx->last != NULL)
8986a03354eSMatthew Dillon 		state_ctx->last->next = state;
8996a03354eSMatthew Dillon 	else
9006a03354eSMatthew Dillon 		state_ctx->state = state;
9016a03354eSMatthew Dillon 
9026a03354eSMatthew Dillon 	state_ctx->last = state;
9036a03354eSMatthew Dillon 	state_ctx->count++;
9046a03354eSMatthew Dillon }
9056a03354eSMatthew Dillon 
9066a03354eSMatthew Dillon /*
9076a03354eSMatthew Dillon  * if rule is NULL
9086a03354eSMatthew Dillon  * 		flush all states
9096a03354eSMatthew Dillon  * else
9106a03354eSMatthew Dillon  * 		flush states which stub is the rule
9116a03354eSMatthew Dillon  */
9126a03354eSMatthew Dillon static void
9136a03354eSMatthew Dillon ipfw_basic_flush_state(struct ip_fw *rule)
9146a03354eSMatthew Dillon {
9156a03354eSMatthew Dillon 	struct ipfw_state_context *state_ctx;
9166a03354eSMatthew Dillon 	struct ip_fw_state *state,*the_state, *prev_state;
9176a03354eSMatthew Dillon 	struct ipfw_context *ctx;
9186a03354eSMatthew Dillon 	int i;
9196a03354eSMatthew Dillon 
9206a03354eSMatthew Dillon 	ctx = ipfw_ctx[mycpuid];
9216a03354eSMatthew Dillon 	for (i = 0; i < state_hash_size; i++) {
9226a03354eSMatthew Dillon 		state_ctx = &ctx->state_ctx[i];
9236a03354eSMatthew Dillon 		if (state_ctx != NULL) {
9246a03354eSMatthew Dillon 			state = state_ctx->state;
9256a03354eSMatthew Dillon 			prev_state = NULL;
9266a03354eSMatthew Dillon 			while (state != NULL) {
9276a03354eSMatthew Dillon 				if (rule != NULL && state->stub != rule) {
9286a03354eSMatthew Dillon 					prev_state = state;
9296a03354eSMatthew Dillon 					state = state->next;
9306a03354eSMatthew Dillon 				} else {
9316a03354eSMatthew Dillon 					if (prev_state == NULL)
9326a03354eSMatthew Dillon 						state_ctx->state = state->next;
9336a03354eSMatthew Dillon 					else
9346a03354eSMatthew Dillon 						prev_state->next = state->next;
9356a03354eSMatthew Dillon 
9366a03354eSMatthew Dillon 					the_state = state;
9376a03354eSMatthew Dillon 					state = state->next;
9386a03354eSMatthew Dillon 					kfree(the_state, M_IPFW3_BASIC);
9396a03354eSMatthew Dillon 					state_ctx->count--;
9406a03354eSMatthew Dillon 					if (state == NULL)
9416a03354eSMatthew Dillon 						state_ctx->last = prev_state;
9426a03354eSMatthew Dillon 
9436a03354eSMatthew Dillon 				}
9446a03354eSMatthew Dillon 			}
9456a03354eSMatthew Dillon 		}
9466a03354eSMatthew Dillon 	}
9476a03354eSMatthew Dillon }
9486a03354eSMatthew Dillon 
9496a03354eSMatthew Dillon /*
9506a03354eSMatthew Dillon  * clean up expired state in every tick
9516a03354eSMatthew Dillon  */
9526a03354eSMatthew Dillon static void
9536a03354eSMatthew Dillon ipfw_cleanup_expired_state(netmsg_t nmsg)
9546a03354eSMatthew Dillon {
9556a03354eSMatthew Dillon 	struct ip_fw_state *state,*the_state,*prev_state;
9566a03354eSMatthew Dillon 	struct ipfw_context *ctx = ipfw_ctx[mycpuid];
9576a03354eSMatthew Dillon 	struct ipfw_state_context *state_ctx;
9586a03354eSMatthew Dillon 	int i;
9596a03354eSMatthew Dillon 
9606a03354eSMatthew Dillon 	for (i = 0; i < state_hash_size; i++) {
9616a03354eSMatthew Dillon 		prev_state = NULL;
9626a03354eSMatthew Dillon 		state_ctx = &(ctx->state_ctx[i]);
9636a03354eSMatthew Dillon 		if (ctx->state_ctx != NULL) {
9646a03354eSMatthew Dillon 			state = state_ctx->state;
9656a03354eSMatthew Dillon 			while (state != NULL) {
9666a03354eSMatthew Dillon 				if (IS_EXPIRED(state)) {
9676a03354eSMatthew Dillon 					if (prev_state == NULL)
9686a03354eSMatthew Dillon 						state_ctx->state = state->next;
9696a03354eSMatthew Dillon 					else
9706a03354eSMatthew Dillon 						prev_state->next = state->next;
9716a03354eSMatthew Dillon 
9726a03354eSMatthew Dillon 					the_state =state;
9736a03354eSMatthew Dillon 					state = state->next;
9746a03354eSMatthew Dillon 
9756a03354eSMatthew Dillon 					if (the_state == state_ctx->last)
9766a03354eSMatthew Dillon 						state_ctx->last = NULL;
9776a03354eSMatthew Dillon 
9786a03354eSMatthew Dillon 
9796a03354eSMatthew Dillon 					kfree(the_state, M_IPFW3_BASIC);
9806a03354eSMatthew Dillon 					state_ctx->count--;
9816a03354eSMatthew Dillon 				} else {
9826a03354eSMatthew Dillon 					prev_state = state;
9836a03354eSMatthew Dillon 					state = state->next;
9846a03354eSMatthew Dillon 				}
9856a03354eSMatthew Dillon 			}
9866a03354eSMatthew Dillon 		}
9876a03354eSMatthew Dillon 	}
9886a03354eSMatthew Dillon 	ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
9896a03354eSMatthew Dillon }
9906a03354eSMatthew Dillon 
9916a03354eSMatthew Dillon static void
9926a03354eSMatthew Dillon ipfw_tick(void *dummy __unused)
9936a03354eSMatthew Dillon {
9946a03354eSMatthew Dillon 	struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg;
9956a03354eSMatthew Dillon 	KKASSERT(mycpuid == IPFW_CFGCPUID);
9966a03354eSMatthew Dillon 
9976a03354eSMatthew Dillon 	crit_enter();
9986a03354eSMatthew Dillon 	KKASSERT(lmsg->ms_flags & MSGF_DONE);
9996a03354eSMatthew Dillon 	if (IPFW_BASIC_LOADED) {
10006a03354eSMatthew Dillon 		lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg);
10016a03354eSMatthew Dillon 		/* ipfw_timeout_netmsg's handler reset this callout */
10026a03354eSMatthew Dillon 	}
10036a03354eSMatthew Dillon 	crit_exit();
10046a03354eSMatthew Dillon 
10056a03354eSMatthew Dillon 	struct netmsg_base *msg;
10066a03354eSMatthew Dillon 	struct netmsg_base the_msg;
10076a03354eSMatthew Dillon 	msg = &the_msg;
10086a03354eSMatthew Dillon 	bzero(msg,sizeof(struct netmsg_base));
10096a03354eSMatthew Dillon 
10106a03354eSMatthew Dillon 	netmsg_init(msg, NULL, &curthread->td_msgport, 0,
10116a03354eSMatthew Dillon 			ipfw_cleanup_expired_state);
10126a03354eSMatthew Dillon 	ifnet_domsg(&msg->lmsg, 0);
10136a03354eSMatthew Dillon }
10146a03354eSMatthew Dillon 
10156a03354eSMatthew Dillon static void
10166a03354eSMatthew Dillon ipfw_tick_dispatch(netmsg_t nmsg)
10176a03354eSMatthew Dillon {
10186a03354eSMatthew Dillon 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
10196a03354eSMatthew Dillon 	KKASSERT(IPFW_BASIC_LOADED);
10206a03354eSMatthew Dillon 
10216a03354eSMatthew Dillon 	/* Reply ASAP */
10226a03354eSMatthew Dillon 	crit_enter();
10236a03354eSMatthew Dillon 	lwkt_replymsg(&nmsg->lmsg, 0);
10246a03354eSMatthew Dillon 	crit_exit();
10256a03354eSMatthew Dillon 
10266a03354eSMatthew Dillon 	callout_reset(&ipfw_tick_callout,
10276a03354eSMatthew Dillon 			state_expiry_check_interval * hz, ipfw_tick, NULL);
10286a03354eSMatthew Dillon }
10296a03354eSMatthew Dillon 
10306a03354eSMatthew Dillon static void
10316a03354eSMatthew Dillon ipfw_basic_init_dispatch(netmsg_t nmsg)
10326a03354eSMatthew Dillon {
10336a03354eSMatthew Dillon 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
10346a03354eSMatthew Dillon 	KKASSERT(IPFW3_LOADED);
10356a03354eSMatthew Dillon 
10366a03354eSMatthew Dillon 	int error = 0;
10376a03354eSMatthew Dillon 	callout_init_mp(&ipfw_tick_callout);
10386a03354eSMatthew Dillon 	netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport,
10396a03354eSMatthew Dillon 			MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch);
10406a03354eSMatthew Dillon 	callout_reset(&ipfw_tick_callout,
10416a03354eSMatthew Dillon 			state_expiry_check_interval * hz, ipfw_tick, NULL);
10426a03354eSMatthew Dillon 	lwkt_replymsg(&nmsg->lmsg, error);
10436a03354eSMatthew Dillon 	ip_fw_basic_loaded=1;
10446a03354eSMatthew Dillon }
10456a03354eSMatthew Dillon 
10466a03354eSMatthew Dillon static int
10476a03354eSMatthew Dillon ipfw_basic_init(void)
10486a03354eSMatthew Dillon {
10496a03354eSMatthew Dillon 	ipfw_basic_flush_state_prt = ipfw_basic_flush_state;
10506a03354eSMatthew Dillon 	ipfw_basic_append_state_prt = ipfw_basic_add_state;
10516a03354eSMatthew Dillon 
10526a03354eSMatthew Dillon 	register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME);
10536a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT,
10546a03354eSMatthew Dillon 			(filter_func)check_count);
10556a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO,
10566a03354eSMatthew Dillon 			(filter_func)check_skipto);
10576a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD,
10586a03354eSMatthew Dillon 			(filter_func)check_forward);
10596a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
10606a03354eSMatthew Dillon 			(filter_func)check_keep_state);
10616a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
10626a03354eSMatthew Dillon 			(filter_func)check_check_state);
10636a03354eSMatthew Dillon 
10646a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10656a03354eSMatthew Dillon 			O_BASIC_IN, (filter_func)check_in);
10666a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10676a03354eSMatthew Dillon 			O_BASIC_OUT, (filter_func)check_out);
10686a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10696a03354eSMatthew Dillon 			O_BASIC_VIA, (filter_func)check_via);
10706a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10716a03354eSMatthew Dillon 			O_BASIC_XMIT, (filter_func)check_via);
10726a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10736a03354eSMatthew Dillon 			O_BASIC_RECV, (filter_func)check_via);
10746a03354eSMatthew Dillon 
10756a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10766a03354eSMatthew Dillon 			O_BASIC_PROTO, (filter_func)check_proto);
10776a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10786a03354eSMatthew Dillon 			O_BASIC_PROB, (filter_func)check_prob);
10796a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10806a03354eSMatthew Dillon 			O_BASIC_IP_SRC, (filter_func)check_from);
10816a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10825284582fSBill Yuan 			O_BASIC_IP_SRC_LOOKUP, (filter_func)check_from_lookup);
10835284582fSBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
108463317b93SBill Yuan 			O_BASIC_IP_SRC_ME, (filter_func)check_from_me);
108563317b93SBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
108663317b93SBill Yuan 			O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask);
108763317b93SBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10886a03354eSMatthew Dillon 			O_BASIC_IP_DST, (filter_func)check_to);
108963317b93SBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10905284582fSBill Yuan 			O_BASIC_IP_DST_LOOKUP, (filter_func)check_to_lookup);
10915284582fSBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
109263317b93SBill Yuan 			O_BASIC_IP_DST_ME, (filter_func)check_to_me);
109363317b93SBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
109463317b93SBill Yuan 			O_BASIC_IP_DST_MASK, (filter_func)check_to_mask);
10956a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10966a03354eSMatthew Dillon 			O_BASIC_TAG, (filter_func)check_tag);
10976a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
10986a03354eSMatthew Dillon 			O_BASIC_UNTAG, (filter_func)check_untag);
10996a03354eSMatthew Dillon 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
11006a03354eSMatthew Dillon 			O_BASIC_TAGGED, (filter_func)check_tagged);
1101*c1bde762SBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1102*c1bde762SBill Yuan 			O_BASIC_IP_SRCPORT, (filter_func)check_src_port);
1103*c1bde762SBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1104*c1bde762SBill Yuan 			O_BASIC_IP_DSTPORT, (filter_func)check_dst_port);
1105*c1bde762SBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1106*c1bde762SBill Yuan 			O_BASIC_IP_SRC_N_PORT, (filter_func)check_src_n_port);
1107*c1bde762SBill Yuan 	register_ipfw_filter_funcs(MODULE_BASIC_ID,
1108*c1bde762SBill Yuan 			O_BASIC_IP_DST_N_PORT, (filter_func)check_dst_n_port);
11096a03354eSMatthew Dillon 
11106a03354eSMatthew Dillon 	int cpu;
11116a03354eSMatthew Dillon 	struct ipfw_context *ctx;
11126a03354eSMatthew Dillon 
11136a03354eSMatthew Dillon 	for (cpu = 0; cpu < ncpus; cpu++) {
11146a03354eSMatthew Dillon 		ctx = ipfw_ctx[cpu];
11156a03354eSMatthew Dillon 		if (ctx != NULL) {
11166a03354eSMatthew Dillon 			ctx->state_ctx = kmalloc(state_hash_size *
11176a03354eSMatthew Dillon 					sizeof(struct ipfw_state_context),
11186a03354eSMatthew Dillon 					M_IPFW3_BASIC, M_WAITOK | M_ZERO);
11196a03354eSMatthew Dillon 			ctx->state_hash_size = state_hash_size;
11206a03354eSMatthew Dillon 		}
11216a03354eSMatthew Dillon 	}
11226a03354eSMatthew Dillon 
11236a03354eSMatthew Dillon 	struct netmsg_base smsg;
11246a03354eSMatthew Dillon 	netmsg_init(&smsg, NULL, &curthread->td_msgport,
11256a03354eSMatthew Dillon 			0, ipfw_basic_init_dispatch);
11266a03354eSMatthew Dillon 	lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
11276a03354eSMatthew Dillon 	return 0;
11286a03354eSMatthew Dillon }
11296a03354eSMatthew Dillon 
11306a03354eSMatthew Dillon static void
11316a03354eSMatthew Dillon ipfw_basic_stop_dispatch(netmsg_t nmsg)
11326a03354eSMatthew Dillon {
11336a03354eSMatthew Dillon 	IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
11346a03354eSMatthew Dillon 	KKASSERT(IPFW3_LOADED);
11356a03354eSMatthew Dillon 	int error = 0;
11366a03354eSMatthew Dillon 	callout_stop(&ipfw_tick_callout);
11376a03354eSMatthew Dillon 	netmsg_service_sync();
11386a03354eSMatthew Dillon 	crit_enter();
11396a03354eSMatthew Dillon 	lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg);
11406a03354eSMatthew Dillon 	crit_exit();
11416a03354eSMatthew Dillon 	lwkt_replymsg(&nmsg->lmsg, error);
11426a03354eSMatthew Dillon 	ip_fw_basic_loaded=0;
11436a03354eSMatthew Dillon }
11446a03354eSMatthew Dillon 
11456a03354eSMatthew Dillon static int
11466a03354eSMatthew Dillon ipfw_basic_stop(void)
11476a03354eSMatthew Dillon {
11486a03354eSMatthew Dillon 	int cpu,i;
11496a03354eSMatthew Dillon 	struct ipfw_state_context *state_ctx;
11506a03354eSMatthew Dillon 	struct ip_fw_state *state,*the_state;
11516a03354eSMatthew Dillon 	struct ipfw_context *ctx;
11526a03354eSMatthew Dillon 	if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) {
11536a03354eSMatthew Dillon 		ipfw_basic_flush_state_prt = NULL;
11546a03354eSMatthew Dillon 		ipfw_basic_append_state_prt = NULL;
11556a03354eSMatthew Dillon 
11566a03354eSMatthew Dillon 		for (cpu = 0; cpu < ncpus; cpu++) {
11576a03354eSMatthew Dillon 			ctx = ipfw_ctx[cpu];
11586a03354eSMatthew Dillon 			if (ctx != NULL) {
11596a03354eSMatthew Dillon 				for (i = 0; i < state_hash_size; i++) {
11606a03354eSMatthew Dillon 					state_ctx = &ctx->state_ctx[i];
11616a03354eSMatthew Dillon 					if (state_ctx != NULL) {
11626a03354eSMatthew Dillon 						state = state_ctx->state;
11636a03354eSMatthew Dillon 						while (state != NULL) {
11646a03354eSMatthew Dillon 							the_state = state;
11656a03354eSMatthew Dillon 							state = state->next;
11666a03354eSMatthew Dillon 							if (the_state ==
11676a03354eSMatthew Dillon 								state_ctx->last)
11686a03354eSMatthew Dillon 							state_ctx->last = NULL;
11696a03354eSMatthew Dillon 
11706a03354eSMatthew Dillon 							kfree(the_state,
11716a03354eSMatthew Dillon 								M_IPFW3_BASIC);
11726a03354eSMatthew Dillon 						}
11736a03354eSMatthew Dillon 					}
11746a03354eSMatthew Dillon 				}
11756a03354eSMatthew Dillon 				ctx->state_hash_size = 0;
11766a03354eSMatthew Dillon 				kfree(ctx->state_ctx, M_IPFW3_BASIC);
11776a03354eSMatthew Dillon 				ctx->state_ctx = NULL;
11786a03354eSMatthew Dillon 			}
11796a03354eSMatthew Dillon 		}
11806a03354eSMatthew Dillon 		struct netmsg_base smsg;
11816a03354eSMatthew Dillon 		netmsg_init(&smsg, NULL, &curthread->td_msgport,
11826a03354eSMatthew Dillon 				0, ipfw_basic_stop_dispatch);
11836a03354eSMatthew Dillon 		return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
11846a03354eSMatthew Dillon 	}
11856a03354eSMatthew Dillon 	return 1;
11866a03354eSMatthew Dillon }
11876a03354eSMatthew Dillon 
11886a03354eSMatthew Dillon 
11896a03354eSMatthew Dillon static int
11906a03354eSMatthew Dillon ipfw3_basic_modevent(module_t mod, int type, void *data)
11916a03354eSMatthew Dillon {
11926a03354eSMatthew Dillon 	int err;
11936a03354eSMatthew Dillon 	switch (type) {
11946a03354eSMatthew Dillon 		case MOD_LOAD:
11956a03354eSMatthew Dillon 			err = ipfw_basic_init();
11966a03354eSMatthew Dillon 			break;
11976a03354eSMatthew Dillon 		case MOD_UNLOAD:
11986a03354eSMatthew Dillon 			err = ipfw_basic_stop();
11996a03354eSMatthew Dillon 			break;
12006a03354eSMatthew Dillon 		default:
12016a03354eSMatthew Dillon 			err = 1;
12026a03354eSMatthew Dillon 	}
12036a03354eSMatthew Dillon 	return err;
12046a03354eSMatthew Dillon }
12056a03354eSMatthew Dillon 
12066a03354eSMatthew Dillon static moduledata_t ipfw3_basic_mod = {
12076a03354eSMatthew Dillon 	"ipfw3_basic",
12086a03354eSMatthew Dillon 	ipfw3_basic_modevent,
12096a03354eSMatthew Dillon 	NULL
12106a03354eSMatthew Dillon };
12116a03354eSMatthew Dillon DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
12126a03354eSMatthew Dillon MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1);
12136a03354eSMatthew Dillon MODULE_VERSION(ipfw3_basic, 1);
1214