2 * Copyright (c) 2014 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Bill Yuan <bycn82@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.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>
47 #include <net/ethernet.h>
48 #include <net/netmsg2.h>
49 #include <net/netisr2.h>
50 #include <net/route.h>
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>
68 #include <net/ipfw3/ip_fw.h>
70 #include "ip_fw3_basic.h"
72 #define TIME_LEQ(a, b) ((int)((a) - (b)) <= 0)
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;
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;
89 static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS);
90 void adjust_hash_size_dispatch(netmsg_t nmsg);
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");
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");
108 ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS)
110 int error, value = 0;
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) {
119 * Make sure we have a power of 2 and
120 * do not allow more than 64k entries.
123 if (value <= 1 || value > 65536) {
126 if ((value & (value - 1)) != 0) {
131 if (state_hash_size != value) {
132 state_hash_size = value;
134 struct netmsg_base *msg, the_msg;
136 bzero(msg,sizeof(struct netmsg_base));
138 netmsg_init(msg, NULL, &curthread->td_msgport,
139 0, adjust_hash_size_dispatch);
140 ifnet_domsg(&msg->lmsg, 0);
147 adjust_hash_size_dispatch(netmsg_t nmsg)
149 struct ipfw_state_context *state_ctx;
150 struct ip_fw_state *the_state, *state;
151 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
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) {
161 kfree(the_state, M_IPFW3_BASIC);
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);
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);
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);
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);
214 hash_packet(struct ipfw_flow_id *id)
217 i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^
218 (id->dst_port) ^ (id->src_port);
219 i &= state_hash_size - 1;
223 static struct ip_fw *
224 lookup_next_rule(struct ip_fw *me)
226 struct ip_fw *rule = NULL;
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)
238 if (rule == NULL) /* failure or not a skipto */
241 me->next_rule = rule;
246 * when all = 1, it will check all the state_ctx
248 static struct ip_fw_state *
249 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all)
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;
256 if (all && cmd->arg1) {
258 end = state_hash_size - 1;
260 start = hash_packet(&args->f_id);
261 end = hash_packet(&args->f_id);
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) {
270 if ((cmd->arg3 == 1 &&
272 state->flow_id.src_ip) ||
275 state->flow_id.src_port) ||
278 state->flow_id.dst_ip) ||
281 state->flow_id.dst_port)) {
284 if (count >= cmd->arg1) {
291 if (fid->proto == state->flow_id.proto) {
293 state->flow_id.src_ip &&
295 state->flow_id.dst_ip &&
297 state->flow_id.src_port ||
298 state->flow_id.src_port == 0) &&
300 state->flow_id.dst_port ||
301 state->flow_id.dst_port == 0)) {
305 state->flow_id.dst_ip &&
307 state->flow_id.src_ip &&
309 state->flow_id.dst_port ||
310 state->flow_id.dst_port == 0) &&
312 state->flow_id.src_port ||
313 state->flow_id.src_port == 0)) {
325 static struct ip_fw_state *
326 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args)
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);
338 state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ;
339 state->timestamp = time_second;
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;
346 state_ctx->state = state;
347 state_ctx->last = state;
354 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
356 if (ifp == NULL) /* no iface with this packet, match fails */
359 /* Check by name or by IP address */
360 if (cmd->name[0] != '\0') { /* match by name */
363 if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
366 if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
370 struct ifaddr_container *ifac;
372 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
373 struct ifaddr *ia = ifac->ifa;
375 if (ia->ifa_addr == NULL)
377 if (ia->ifa_addr->sa_family != AF_INET)
379 if (cmd->p.ip.s_addr ==
380 ((struct sockaddr_in *)
381 (ia->ifa_addr))->sin_addr.s_addr)
382 return(1); /* match */
386 return 0; /* no match, fail ... */
389 /* implimentation of the checker functions */
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)
395 (*f)->bcnt += ip_len;
396 (*f)->timestamp = time_second;
397 *cmd_ctl = IP_FW_CTL_NEXT;
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)
405 (*f)->bcnt += ip_len;
406 (*f)->timestamp = time_second;
407 if ((*f)->next_rule == NULL)
408 lookup_next_rule(*f);
410 *cmd_ctl = IP_FW_CTL_AGAIN;
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)
417 struct sockaddr_in *sin, *sa;
420 if ((*args)->eh) { /* not valid on layer2 pkts */
421 *cmd_ctl=IP_FW_CTL_NEXT;
426 (*f)->bcnt += ip_len;
427 (*f)->timestamp = time_second;
428 if ((*f)->next_rule == NULL)
429 lookup_next_rule(*f);
431 mtag = m_tag_get(PACKET_TAG_IPFORWARD,
432 sizeof(*sin), M_NOWAIT);
434 *cmd_val = IP_FW_DENY;
435 *cmd_ctl = IP_FW_CTL_DONE;
438 sin = m_tag_data(mtag);
439 sa = &((ipfw_insn_sa *)cmd)->sa;
440 /* arg3: count of the dest, arg1: type of fwd */
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);
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;
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)
465 struct ip_fw_state *state=NULL;
467 state = lookup_state(*args, cmd, &limited, 0);
470 state->bcnt += ip_len;
471 state->timestamp = time_second;
473 (*f)->bcnt += ip_len;
474 (*f)->timestamp = time_second;
476 *cmd_ctl = IP_FW_CTL_CHK_STATE;
478 *cmd_ctl = IP_FW_CTL_NEXT;
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)
486 *cmd_ctl = IP_FW_CTL_NO;
487 *cmd_val = ((*args)->oif == NULL);
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)
494 *cmd_ctl = IP_FW_CTL_NO;
495 *cmd_val = ((*args)->oif != NULL);
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)
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);
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)
512 *cmd_ctl = IP_FW_CTL_NO;
513 *cmd_val = ((*args)->f_id.proto == cmd->arg1);
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)
520 *cmd_ctl = IP_FW_CTL_NO;
521 *cmd_val = (krandom() % 100) < cmd->arg1;
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)
528 struct in_addr src_ip;
530 struct mbuf *m = (*args)->m;
531 struct ip *ip = mtod(m, struct ip *);
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;
538 *cmd_val = (hlen > 0 &&
539 ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
540 *cmd_ctl = IP_FW_CTL_NO;
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)
547 struct in_addr dst_ip;
549 struct mbuf *m = (*args)->m;
550 struct ip *ip = mtod(m, struct ip *);
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;
557 *cmd_val = (hlen > 0 &&
558 ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
559 *cmd_ctl = IP_FW_CTL_NO;
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)
566 struct ip_fw_state *state;
569 *cmd_ctl = IP_FW_CTL_NO;
570 state = lookup_state(*args, cmd, &limited, 1);
572 *cmd_val = IP_FW_NOT_MATCH;
575 state = install_state(*f, cmd, *args);
579 state->bcnt += ip_len;
580 state->timestamp = time_second;
581 *cmd_val = IP_FW_MATCH;
583 *cmd_val = IP_FW_NOT_MATCH;
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)
592 struct m_tag *mtag = m_tag_locate((*args)->m,
593 MTAG_IPFW, cmd->arg1, NULL);
595 mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT);
597 m_tag_prepend((*args)->m, mtag);
601 (*f)->bcnt += ip_len;
602 (*f)->timestamp = time_second;
603 *cmd_ctl = IP_FW_CTL_NEXT;
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)
610 struct m_tag *mtag = m_tag_locate((*args)->m,
611 MTAG_IPFW, cmd->arg1, NULL);
613 m_tag_delete((*args)->m, mtag);
616 (*f)->bcnt += ip_len;
617 (*f)->timestamp = time_second;
618 *cmd_ctl = IP_FW_CTL_NEXT;
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)
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;
629 *cmd_val = IP_FW_NOT_MATCH;
633 ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state)
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) {
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;
663 state_ctx->state = state;
665 state_ctx->last = state;
673 * flush states which stub is the rule
676 ipfw_basic_flush_state(struct ip_fw *rule)
678 struct ipfw_state_context *state_ctx;
679 struct ip_fw_state *state,*the_state, *prev_state;
680 struct ipfw_context *ctx;
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;
689 while (state != NULL) {
690 if (rule != NULL && state->stub != rule) {
694 if (prev_state == NULL)
695 state_ctx->state = state->next;
697 prev_state->next = state->next;
701 kfree(the_state, M_IPFW3_BASIC);
704 state_ctx->last = prev_state;
713 * clean up expired state in every tick
716 ipfw_cleanup_expired_state(netmsg_t nmsg)
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;
723 for (i = 0; i < state_hash_size; i++) {
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;
733 prev_state->next = state->next;
738 if (the_state == state_ctx->last)
739 state_ctx->last = NULL;
742 kfree(the_state, M_IPFW3_BASIC);
751 ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
755 ipfw_tick(void *dummy __unused)
757 struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg;
758 KKASSERT(mycpuid == IPFW_CFGCPUID);
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 */
768 struct netmsg_base *msg;
769 struct netmsg_base the_msg;
771 bzero(msg,sizeof(struct netmsg_base));
773 netmsg_init(msg, NULL, &curthread->td_msgport, 0,
774 ipfw_cleanup_expired_state);
775 ifnet_domsg(&msg->lmsg, 0);
779 ipfw_tick_dispatch(netmsg_t nmsg)
781 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
782 KKASSERT(IPFW_BASIC_LOADED);
786 lwkt_replymsg(&nmsg->lmsg, 0);
789 callout_reset(&ipfw_tick_callout,
790 state_expiry_check_interval * hz, ipfw_tick, NULL);
794 ipfw_basic_init_dispatch(netmsg_t nmsg)
796 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
797 KKASSERT(IPFW3_LOADED);
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;
810 ipfw_basic_init(void)
812 ipfw_basic_flush_state_prt = ipfw_basic_flush_state;
813 ipfw_basic_append_state_prt = ipfw_basic_add_state;
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);
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);
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);
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);
855 struct ipfw_context *ctx;
857 for (cpu = 0; cpu < ncpus; cpu++) {
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;
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);
875 ipfw_basic_stop_dispatch(netmsg_t nmsg)
877 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
878 KKASSERT(IPFW3_LOADED);
880 callout_stop(&ipfw_tick_callout);
881 netmsg_service_sync();
883 lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg);
885 lwkt_replymsg(&nmsg->lmsg, error);
886 ip_fw_basic_loaded=0;
890 ipfw_basic_stop(void)
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;
900 for (cpu = 0; cpu < ncpus; cpu++) {
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) {
912 state_ctx->last = NULL;
919 ctx->state_hash_size = 0;
920 kfree(ctx->state_ctx, M_IPFW3_BASIC);
921 ctx->state_ctx = NULL;
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);
934 ipfw3_basic_modevent(module_t mod, int type, void *data)
939 err = ipfw_basic_init();
942 err = ipfw_basic_stop();
950 static moduledata_t ipfw3_basic_mod = {
952 ipfw3_basic_modevent,
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);