kernel - Fix callout_stop/callout_reset rearm race
[dragonfly.git] / sys / net / ipfw3_basic / ip_fw3_basic.c
blob76516f229ffbc6a2ceba9102347b0d30d8365eb5
1 /*
2 * Copyright (c) 2014 - 2017 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Bill Yuan <bycn82@dragonflybsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
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.
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>
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>
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>
69 #include <net/ipfw3/ip_fw3_table.h>
70 #include <net/ipfw3/ip_fw3_sync.h>
72 #include "ip_fw3_basic.h"
74 #define TIME_LEQ(a, b) ((int)((a) - (b)) <= 0)
76 extern struct ipfw_context *ipfw_ctx[MAXCPU];
77 extern struct ipfw_sync_context sync_ctx;
78 extern int fw_verbose;
79 extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt;
80 extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt;
81 extern ipfw_sync_send_state_t *ipfw_sync_send_state_prt;
82 extern ipfw_sync_install_state_t *ipfw_sync_install_state_prt;
84 static int ip_fw_basic_loaded;
85 static struct netmsg_base ipfw_timeout_netmsg; /* schedule ipfw timeout */
86 static struct callout ipfw_tick_callout;
87 static int state_lifetime = 20;
88 static int state_expiry_check_interval = 10;
89 static int state_count_max = 4096;
90 static int state_hash_size_old = 0;
91 static int state_hash_size = 4096;
94 static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS);
95 void adjust_hash_size_dispatch(netmsg_t nmsg);
97 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic,
98 CTLFLAG_RW, 0, "Firewall Basic");
99 SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size,
100 CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0,
101 ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size");
103 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW,
104 &state_lifetime, 0, "default life time");
105 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO,
106 state_expiry_check_interval, CTLFLAG_RW,
107 &state_expiry_check_interval, 0,
108 "default state expiry check interval");
109 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW,
110 &state_count_max, 0, "maximum of state");
112 static int
113 ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS)
115 int error, value = 0;
117 state_hash_size_old = state_hash_size;
118 value = state_hash_size;
119 error = sysctl_handle_int(oidp, &value, 0, req);
120 if (error || !req->newptr) {
121 goto back;
124 * Make sure we have a power of 2 and
125 * do not allow more than 64k entries.
127 error = EINVAL;
128 if (value <= 1 || value > 65536) {
129 goto back;
131 if ((value & (value - 1)) != 0) {
132 goto back;
135 error = 0;
136 if (state_hash_size != value) {
137 state_hash_size = value;
139 struct netmsg_base *msg, the_msg;
140 msg = &the_msg;
141 bzero(msg,sizeof(struct netmsg_base));
143 netmsg_init(msg, NULL, &curthread->td_msgport,
144 0, adjust_hash_size_dispatch);
145 netisr_domsg(msg, 0);
147 back:
148 return error;
151 void
152 adjust_hash_size_dispatch(netmsg_t nmsg)
154 struct ipfw_state_context *state_ctx;
155 struct ip_fw_state *the_state, *state;
156 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
157 int i;
159 for (i = 0; i < state_hash_size_old; i++) {
160 state_ctx = &ctx->state_ctx[i];
161 if (state_ctx != NULL) {
162 state = state_ctx->state;
163 while (state != NULL) {
164 the_state = state;
165 state = state->next;
166 kfree(the_state, M_IPFW3_BASIC);
167 the_state = NULL;
171 kfree(ctx->state_ctx,M_IPFW3_BASIC);
172 ctx->state_ctx = kmalloc(state_hash_size *
173 sizeof(struct ipfw_state_context),
174 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
175 ctx->state_hash_size = state_hash_size;
176 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
180 /* prototype of the checker functions */
181 void check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
182 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
183 void check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
184 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
185 void check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
186 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
187 void check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
188 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
190 void check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
191 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
192 void check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
193 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
194 void check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
195 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
196 void check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
197 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
198 void check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
199 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
200 void check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
201 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
202 void check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
203 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
204 void check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
205 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
206 void check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
207 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
208 void check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
209 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
210 void check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
211 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
212 void check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
213 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
214 void check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
215 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
216 void check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
217 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
218 void check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
219 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
220 void check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
221 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
222 void check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
223 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
224 void check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
225 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
226 void check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
227 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
228 void check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
229 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
230 void check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
231 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
233 /* prototype of the utility functions */
234 int match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid,
235 struct ip_fw_state *state);
236 int count_match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid,
237 struct ip_fw_state *state, int *count);
239 static struct ip_fw *lookup_next_rule(struct ip_fw *me);
240 static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd);
241 static __inline int hash_packet(struct ipfw_flow_id *id);
243 static __inline int
244 hash_packet(struct ipfw_flow_id *id)
246 uint32_t i;
247 i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^
248 (id->dst_port) ^ (id->src_port);
249 i &= state_hash_size - 1;
250 return i;
253 static struct ip_fw *
254 lookup_next_rule(struct ip_fw *me)
256 struct ip_fw *rule = NULL;
257 ipfw_insn *cmd;
259 /* look for action, in case it is a skipto */
260 cmd = ACTION_PTR(me);
261 if ((int)cmd->module == MODULE_BASIC_ID &&
262 (int)cmd->opcode == O_BASIC_SKIPTO) {
263 for (rule = me->next; rule; rule = rule->next) {
264 if (rule->rulenum >= cmd->arg1)
265 break;
268 if (rule == NULL) /* failure or not a skipto */
269 rule = me->next;
271 me->next_rule = rule;
272 return rule;
276 * return value
277 * 0 : not match 1: same direction 2: reverse direction
280 match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid, struct ip_fw_state *state)
282 if (fid->src_ip == state->flow_id.src_ip &&
283 fid->dst_ip == state->flow_id.dst_ip &&
284 (fid->src_port == state->flow_id.src_port ||
285 state->flow_id.src_port == 0) &&
286 (fid->dst_port == state->flow_id.dst_port ||
287 state->flow_id.dst_port == 0)) {
288 return 1;
290 if (fid->src_ip == state->flow_id.dst_ip &&
291 fid->dst_ip == state->flow_id.src_ip &&
292 (fid->src_port == state->flow_id.dst_port ||
293 state->flow_id.dst_port == 0) &&
294 (fid->dst_port == state->flow_id.src_port ||
295 state->flow_id.src_port == 0)) {
296 return 2;
298 return 0;
302 * return 1 when more states than limit
303 * arg3: limit type (1=src ip, 2=src port, 3=dst ip, 4=dst port)
304 * arg1: limit
307 count_match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid,
308 struct ip_fw_state *state, int *count)
310 if ((cmd->arg3 == 1 && fid->src_ip == state->flow_id.src_ip) ||
311 (cmd->arg3 == 2 && fid->src_port == state->flow_id.src_port) ||
312 (cmd->arg3 == 3 && fid->dst_ip == state->flow_id.dst_ip) ||
313 (cmd->arg3 == 4 && fid->dst_port == state->flow_id.dst_port)) {
314 *count = *count + 1;
315 if (*count >= cmd->arg1)
316 return 1;
318 return 0;
322 * when all = 1, it will check all the state_ctx
323 * all = 1 during keep-state
324 * all = 0 during check-state
326 * in the cmd of keep_state
327 * arg3=type arg1=limit
329 static struct ip_fw_state *
330 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all)
332 struct ip_fw_state *state = NULL;
333 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
334 struct ipfw_state_context *state_ctx;
335 int start, end, i, count = 0;
337 if (all && cmd->arg1) {
338 start = 0;
339 end = state_hash_size - 1;
340 } else {
341 start = hash_packet(&args->f_id);
342 end = hash_packet(&args->f_id);
345 for (i = start; i <= end; i++) {
346 state_ctx = &ctx->state_ctx[i];
347 if (state_ctx != NULL) {
348 state = state_ctx->state;
349 struct ipfw_flow_id *fid = &args->f_id;
350 while (state != NULL) {
351 /* has limit and already exceed the limit */
352 if (cmd->arg1 &&
353 count_match_state(cmd, fid,
354 state, &count) != 0) {
355 *limited = 1;
356 goto done;
359 if (fid->proto == state->flow_id.proto &&
360 match_state(cmd, fid, state) != 0)
361 goto done;
363 state = state->next;
367 done:
368 return state;
371 static struct ip_fw_state *
372 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args)
374 struct ip_fw_state *state;
375 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
376 struct ipfw_state_context *state_ctx;
377 int hash = hash_packet(&args->f_id);
378 state_ctx = &ctx->state_ctx[hash];
379 state = kmalloc(sizeof(struct ip_fw_state),
380 M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
381 if (state == NULL) {
382 return NULL;
384 state->stub = rule;
385 state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ;
386 state->timestamp = time_second;
387 state->expiry = 0;
388 bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id));
389 //append the state into the state chian
390 if (state_ctx->last != NULL)
391 state_ctx->last->next = state;
392 else
393 state_ctx->state = state;
394 state_ctx->last = state;
395 state_ctx->count++;
397 if (sync_ctx.running & 2) {
398 ipfw_sync_send_state_prt(state, mycpuid, hash);
400 return state;
403 void
404 ipfw_sync_install_state(struct cmd_send_state *cmd)
406 struct ip_fw_state *state;
407 struct ipfw_context *ctx = ipfw_ctx[cmd->cpu];
408 struct ipfw_state_context *state_ctx;
409 struct ip_fw *rule;
411 state_ctx = &ctx->state_ctx[cmd->hash];
412 state = kmalloc(sizeof(struct ip_fw_state),
413 M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
414 if (state == NULL) {
415 return;
417 for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
418 if (rule->rulenum == cmd->rulenum) {
419 goto found;
422 return;
423 found:
424 state->stub = rule;
425 state->lifetime = cmd->lifetime;
426 state->timestamp = time_second;
427 state->expiry = 0;
428 bcopy(&cmd->flow, &state->flow_id, sizeof(struct ipfw_flow_id));
429 //append the state into the state chian
430 if (state_ctx->last != NULL)
431 state_ctx->last->next = state;
432 else
433 state_ctx->state = state;
434 state_ctx->last = state;
435 state_ctx->count++;
438 static int
439 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
441 if (ifp == NULL) /* no iface with this packet, match fails */
442 return 0;
444 /* Check by name or by IP address */
445 if (cmd->name[0] != '\0') { /* match by name */
446 /* Check name */
447 if (cmd->p.glob) {
448 if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
449 return(1);
450 } else {
451 if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
452 return(1);
454 } else {
455 struct ifaddr_container *ifac;
457 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
458 struct ifaddr *ia = ifac->ifa;
460 if (ia->ifa_addr == NULL)
461 continue;
462 if (ia->ifa_addr->sa_family != AF_INET)
463 continue;
464 if (cmd->p.ip.s_addr ==
465 ((struct sockaddr_in *)
466 (ia->ifa_addr))->sin_addr.s_addr)
467 return(1); /* match */
471 return 0; /* no match, fail ... */
474 /* implimentation of the checker functions */
475 void
476 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
477 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
479 (*f)->pcnt++;
480 (*f)->bcnt += ip_len;
481 (*f)->timestamp = time_second;
482 *cmd_ctl = IP_FW_CTL_NEXT;
485 void
486 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
487 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
489 (*f)->pcnt++;
490 (*f)->bcnt += ip_len;
491 (*f)->timestamp = time_second;
492 if ((*f)->next_rule == NULL)
493 lookup_next_rule(*f);
494 *f = (*f)->next_rule;
495 *cmd_ctl = IP_FW_CTL_AGAIN;
498 void
499 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
500 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
502 struct sockaddr_in *sin, *sa;
503 struct m_tag *mtag;
505 if ((*args)->eh) { /* not valid on layer2 pkts */
506 *cmd_ctl=IP_FW_CTL_NEXT;
507 return;
510 (*f)->pcnt++;
511 (*f)->bcnt += ip_len;
512 (*f)->timestamp = time_second;
513 if ((*f)->next_rule == NULL)
514 lookup_next_rule(*f);
516 mtag = m_tag_get(PACKET_TAG_IPFORWARD,
517 sizeof(*sin), M_NOWAIT);
518 if (mtag == NULL) {
519 *cmd_val = IP_FW_DENY;
520 *cmd_ctl = IP_FW_CTL_DONE;
521 return;
523 sin = m_tag_data(mtag);
524 sa = &((ipfw_insn_sa *)cmd)->sa;
525 /* arg3: count of the dest, arg1: type of fwd */
526 int i = 0;
527 if(cmd->arg3 > 1) {
528 if (cmd->arg1 == 0) { /* type: random */
529 i = krandom() % cmd->arg3;
530 } else if (cmd->arg1 == 1) { /* type: round-robin */
531 i = cmd->arg2++ % cmd->arg3;
532 } else if (cmd->arg1 == 2) { /* type: sticky */
533 struct ip *ip = mtod((*args)->m, struct ip *);
534 i = ip->ip_src.s_addr & (cmd->arg3 - 1);
536 sa += i;
538 *sin = *sa; /* apply the destination */
539 m_tag_prepend((*args)->m, mtag);
540 (*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED;
541 (*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
542 *cmd_ctl = IP_FW_CTL_DONE;
543 *cmd_val = IP_FW_PASS;
546 void
547 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
548 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
550 struct ip_fw_state *state=NULL;
551 int limited = 0 ;
552 state = lookup_state(*args, cmd, &limited, 0);
553 if (state != NULL) {
554 state->pcnt++;
555 state->bcnt += ip_len;
556 state->timestamp = time_second;
557 (*f)->pcnt++;
558 (*f)->bcnt += ip_len;
559 (*f)->timestamp = time_second;
560 *f = state->stub;
561 *cmd_ctl = IP_FW_CTL_CHK_STATE;
562 } else {
563 *cmd_ctl = IP_FW_CTL_NEXT;
567 void
568 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
569 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
571 *cmd_ctl = IP_FW_CTL_NO;
572 *cmd_val = ((*args)->oif == NULL);
575 void
576 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
577 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
579 *cmd_ctl = IP_FW_CTL_NO;
580 *cmd_val = ((*args)->oif != NULL);
583 void
584 check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
585 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
587 *cmd_ctl = IP_FW_CTL_NO;
588 *cmd_val = iface_match((*args)->oif ?
589 (*args)->oif : (*args)->m->m_pkthdr.rcvif,
590 (ipfw_insn_if *)cmd);
593 void
594 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
595 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
597 *cmd_ctl = IP_FW_CTL_NO;
598 *cmd_val = ((*args)->f_id.proto == cmd->arg1);
601 void
602 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
603 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
605 *cmd_ctl = IP_FW_CTL_NO;
606 *cmd_val = (krandom() % 100) < cmd->arg1;
609 void
610 check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
611 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
613 struct in_addr src_ip;
614 u_int hlen = 0;
615 struct mbuf *m = (*args)->m;
616 struct ip *ip = mtod(m, struct ip *);
617 src_ip = ip->ip_src;
618 if ((*args)->eh == NULL ||
619 (m->m_pkthdr.len >= sizeof(struct ip) &&
620 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
621 hlen = ip->ip_hl << 2;
623 *cmd_val = (hlen > 0 &&
624 ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
625 *cmd_ctl = IP_FW_CTL_NO;
628 void
629 check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
630 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
632 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
633 struct ipfw_table_context *table_ctx;
634 struct radix_node_head *rnh;
635 struct sockaddr_in sa;
637 struct mbuf *m = (*args)->m;
638 struct ip *ip = mtod(m, struct ip *);
639 struct in_addr src_ip = ip->ip_src;
641 *cmd_val = IP_FW_NOT_MATCH;
643 table_ctx = ctx->table_ctx;
644 table_ctx += cmd->arg1;
646 if (table_ctx->type != 0) {
647 rnh = table_ctx->node;
648 sa.sin_len = 8;
649 sa.sin_addr.s_addr = src_ip.s_addr;
650 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
651 *cmd_val = IP_FW_MATCH;
653 *cmd_ctl = IP_FW_CTL_NO;
656 void
657 check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
658 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
660 struct in_addr src_ip;
661 u_int hlen = 0;
662 struct mbuf *m = (*args)->m;
663 struct ip *ip = mtod(m, struct ip *);
664 src_ip = ip->ip_src;
665 if ((*args)->eh == NULL ||
666 (m->m_pkthdr.len >= sizeof(struct ip) &&
667 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
668 hlen = ip->ip_hl << 2;
670 *cmd_ctl = IP_FW_CTL_NO;
671 if (hlen > 0) {
672 struct ifnet *tif;
673 tif = INADDR_TO_IFP(&src_ip);
674 *cmd_val = (tif != NULL);
675 } else {
676 *cmd_val = IP_FW_NOT_MATCH;
680 void
681 check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
682 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
684 struct in_addr src_ip;
685 u_int hlen = 0;
686 struct mbuf *m = (*args)->m;
687 struct ip *ip = mtod(m, struct ip *);
688 src_ip = ip->ip_src;
689 if ((*args)->eh == NULL ||
690 (m->m_pkthdr.len >= sizeof(struct ip) &&
691 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
692 hlen = ip->ip_hl << 2;
695 *cmd_ctl = IP_FW_CTL_NO;
696 *cmd_val = (hlen > 0 &&
697 ((ipfw_insn_ip *)cmd)->addr.s_addr ==
698 (src_ip.s_addr &
699 ((ipfw_insn_ip *)cmd)->mask.s_addr));
702 void
703 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
704 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
706 struct in_addr dst_ip;
707 u_int hlen = 0;
708 struct mbuf *m = (*args)->m;
709 struct ip *ip = mtod(m, struct ip *);
710 dst_ip = ip->ip_dst;
711 if ((*args)->eh == NULL ||
712 (m->m_pkthdr.len >= sizeof(struct ip) &&
713 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
714 hlen = ip->ip_hl << 2;
716 *cmd_val = (hlen > 0 &&
717 ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
718 *cmd_ctl = IP_FW_CTL_NO;
721 void
722 check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
723 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
725 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
726 struct ipfw_table_context *table_ctx;
727 struct radix_node_head *rnh;
728 struct sockaddr_in sa;
730 struct mbuf *m = (*args)->m;
731 struct ip *ip = mtod(m, struct ip *);
732 struct in_addr dst_ip = ip->ip_dst;
734 *cmd_val = IP_FW_NOT_MATCH;
736 table_ctx = ctx->table_ctx;
737 table_ctx += cmd->arg1;
739 if (table_ctx->type != 0) {
740 rnh = table_ctx->node;
741 sa.sin_len = 8;
742 sa.sin_addr.s_addr = dst_ip.s_addr;
743 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
744 *cmd_val = IP_FW_MATCH;
746 *cmd_ctl = IP_FW_CTL_NO;
749 void
750 check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
751 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
753 struct in_addr dst_ip;
754 u_int hlen = 0;
755 struct mbuf *m = (*args)->m;
756 struct ip *ip = mtod(m, struct ip *);
757 dst_ip = ip->ip_src;
758 if ((*args)->eh == NULL ||
759 (m->m_pkthdr.len >= sizeof(struct ip) &&
760 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
761 hlen = ip->ip_hl << 2;
763 *cmd_ctl = IP_FW_CTL_NO;
764 if (hlen > 0) {
765 struct ifnet *tif;
766 tif = INADDR_TO_IFP(&dst_ip);
767 *cmd_val = (tif != NULL);
768 } else {
769 *cmd_val = IP_FW_NOT_MATCH;
773 void
774 check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
775 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
777 struct in_addr dst_ip;
778 u_int hlen = 0;
779 struct mbuf *m = (*args)->m;
780 struct ip *ip = mtod(m, struct ip *);
781 dst_ip = ip->ip_src;
782 if ((*args)->eh == NULL ||
783 (m->m_pkthdr.len >= sizeof(struct ip) &&
784 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
785 hlen = ip->ip_hl << 2;
788 *cmd_ctl = IP_FW_CTL_NO;
789 *cmd_val = (hlen > 0 &&
790 ((ipfw_insn_ip *)cmd)->addr.s_addr ==
791 (dst_ip.s_addr &
792 ((ipfw_insn_ip *)cmd)->mask.s_addr));
795 void
796 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
797 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
799 struct ip_fw_state *state;
800 int limited = 0;
802 *cmd_ctl = IP_FW_CTL_NO;
803 *cmd_val = IP_FW_MATCH;
804 state = lookup_state(*args, cmd, &limited, 1);
805 if (limited != 1) {
806 if (state == NULL)
807 state = install_state(*f, cmd, *args);
809 if (state != NULL) {
810 state->pcnt++;
811 state->bcnt += ip_len;
812 state->timestamp = time_second;
817 void
818 check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
819 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
821 struct m_tag *mtag = m_tag_locate((*args)->m,
822 MTAG_IPFW, cmd->arg1, NULL);
823 if (mtag == NULL) {
824 mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT);
825 if (mtag != NULL)
826 m_tag_prepend((*args)->m, mtag);
829 (*f)->pcnt++;
830 (*f)->bcnt += ip_len;
831 (*f)->timestamp = time_second;
832 *cmd_ctl = IP_FW_CTL_NEXT;
835 void
836 check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
837 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
839 struct m_tag *mtag = m_tag_locate((*args)->m,
840 MTAG_IPFW, cmd->arg1, NULL);
841 if (mtag != NULL)
842 m_tag_delete((*args)->m, mtag);
844 (*f)->pcnt++;
845 (*f)->bcnt += ip_len;
846 (*f)->timestamp = time_second;
847 *cmd_ctl = IP_FW_CTL_NEXT;
850 void
851 check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
852 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
854 *cmd_ctl = IP_FW_CTL_NO;
855 if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL )
856 *cmd_val = IP_FW_MATCH;
857 else
858 *cmd_val = IP_FW_NOT_MATCH;
861 void
862 check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
863 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
865 *cmd_ctl = IP_FW_CTL_NO;
866 if ((*args)->f_id.src_port == cmd->arg1)
867 *cmd_val = IP_FW_MATCH;
868 else
869 *cmd_val = IP_FW_NOT_MATCH;
872 void
873 check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
874 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
876 *cmd_ctl = IP_FW_CTL_NO;
877 if ((*args)->f_id.dst_port == cmd->arg1)
878 *cmd_val = IP_FW_MATCH;
879 else
880 *cmd_val = IP_FW_NOT_MATCH;
883 void
884 check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
885 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
887 struct in_addr src_ip;
888 u_int hlen = 0;
889 struct mbuf *m = (*args)->m;
890 struct ip *ip = mtod(m, struct ip *);
891 src_ip = ip->ip_src;
892 if ((*args)->eh == NULL ||
893 (m->m_pkthdr.len >= sizeof(struct ip) &&
894 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
895 hlen = ip->ip_hl << 2;
897 *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
898 *cmd_ctl = IP_FW_CTL_NO;
899 if (*cmd_val && (*args)->f_id.src_port == cmd->arg1)
900 *cmd_val = IP_FW_MATCH;
901 else
902 *cmd_val = IP_FW_NOT_MATCH;
905 void
906 check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
907 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
909 struct in_addr dst_ip;
910 u_int hlen = 0;
911 struct mbuf *m = (*args)->m;
912 struct ip *ip = mtod(m, struct ip *);
913 dst_ip = ip->ip_dst;
914 if ((*args)->eh == NULL ||
915 (m->m_pkthdr.len >= sizeof(struct ip) &&
916 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
917 hlen = ip->ip_hl << 2;
919 *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
920 *cmd_ctl = IP_FW_CTL_NO;
921 if (*cmd_val && (*args)->f_id.dst_port == cmd->arg1)
922 *cmd_val = IP_FW_MATCH;
923 else
924 *cmd_val = IP_FW_NOT_MATCH;
929 static void
930 ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state)
932 struct ip_fw_state *state;
933 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
934 struct ipfw_state_context *state_ctx;
935 state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))];
936 state = kmalloc(sizeof(struct ip_fw_state),
937 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
938 struct ip_fw *rule = ctx->ipfw_rule_chain;
939 while (rule != NULL) {
940 if (rule->rulenum == ioc_state->rulenum) {
941 break;
943 rule = rule->next;
945 if (rule == NULL)
946 return;
948 state->stub = rule;
950 state->lifetime = ioc_state->lifetime == 0 ?
951 state_lifetime : ioc_state->lifetime ;
952 state->timestamp = time_second;
953 state->expiry = ioc_state->expiry;
954 bcopy(&ioc_state->flow_id, &state->flow_id,
955 sizeof(struct ipfw_flow_id));
956 //append the state into the state chian
957 if (state_ctx->last != NULL)
958 state_ctx->last->next = state;
959 else
960 state_ctx->state = state;
962 state_ctx->last = state;
963 state_ctx->count++;
967 * if rule is NULL
968 * flush all states
969 * else
970 * flush states which stub is the rule
972 static void
973 ipfw_basic_flush_state(struct ip_fw *rule)
975 struct ipfw_state_context *state_ctx;
976 struct ip_fw_state *state,*the_state, *prev_state;
977 struct ipfw_context *ctx;
978 int i;
980 ctx = ipfw_ctx[mycpuid];
981 for (i = 0; i < state_hash_size; i++) {
982 state_ctx = &ctx->state_ctx[i];
983 if (state_ctx != NULL) {
984 state = state_ctx->state;
985 prev_state = NULL;
986 while (state != NULL) {
987 if (rule != NULL && state->stub != rule) {
988 prev_state = state;
989 state = state->next;
990 } else {
991 if (prev_state == NULL)
992 state_ctx->state = state->next;
993 else
994 prev_state->next = state->next;
996 the_state = state;
997 state = state->next;
998 kfree(the_state, M_IPFW3_BASIC);
999 state_ctx->count--;
1000 if (state == NULL)
1001 state_ctx->last = prev_state;
1010 * clean up expired state in every tick
1012 static void
1013 ipfw_cleanup_expired_state(netmsg_t nmsg)
1015 struct ip_fw_state *state,*the_state,*prev_state;
1016 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
1017 struct ipfw_state_context *state_ctx;
1018 int i;
1020 for (i = 0; i < state_hash_size; i++) {
1021 prev_state = NULL;
1022 state_ctx = &(ctx->state_ctx[i]);
1023 if (ctx->state_ctx != NULL) {
1024 state = state_ctx->state;
1025 while (state != NULL) {
1026 if (IS_EXPIRED(state)) {
1027 if (prev_state == NULL)
1028 state_ctx->state = state->next;
1029 else
1030 prev_state->next = state->next;
1032 the_state =state;
1033 state = state->next;
1035 if (the_state == state_ctx->last)
1036 state_ctx->last = NULL;
1039 kfree(the_state, M_IPFW3_BASIC);
1040 state_ctx->count--;
1041 } else {
1042 prev_state = state;
1043 state = state->next;
1048 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
1051 static void
1052 ipfw_tick(void *dummy __unused)
1054 struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg;
1055 KKASSERT(mycpuid == IPFW_CFGCPUID);
1057 crit_enter();
1058 KKASSERT(lmsg->ms_flags & MSGF_DONE);
1059 if (IPFW_BASIC_LOADED) {
1060 lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg);
1061 /* ipfw_timeout_netmsg's handler reset this callout */
1063 crit_exit();
1066 static void
1067 ipfw_tick_dispatch(netmsg_t nmsg)
1069 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1070 KKASSERT(IPFW_BASIC_LOADED);
1072 /* Reply ASAP */
1073 crit_enter();
1074 lwkt_replymsg(&nmsg->lmsg, 0);
1075 crit_exit();
1077 callout_reset(&ipfw_tick_callout,
1078 state_expiry_check_interval * hz, ipfw_tick, NULL);
1080 struct netmsg_base msg;
1081 netmsg_init(&msg, NULL, &curthread->td_msgport, 0,
1082 ipfw_cleanup_expired_state);
1083 netisr_domsg(&msg, 0);
1086 static void
1087 ipfw_basic_init_dispatch(netmsg_t nmsg)
1089 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1090 KKASSERT(IPFW3_LOADED);
1092 int error = 0;
1093 callout_init_mp(&ipfw_tick_callout);
1094 netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport,
1095 MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch);
1096 callout_reset(&ipfw_tick_callout,
1097 state_expiry_check_interval * hz, ipfw_tick, NULL);
1098 lwkt_replymsg(&nmsg->lmsg, error);
1099 ip_fw_basic_loaded=1;
1102 static int
1103 ipfw_basic_init(void)
1105 ipfw_basic_flush_state_prt = ipfw_basic_flush_state;
1106 ipfw_basic_append_state_prt = ipfw_basic_add_state;
1107 ipfw_sync_install_state_prt = ipfw_sync_install_state;
1109 register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME);
1110 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT,
1111 (filter_func)check_count);
1112 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO,
1113 (filter_func)check_skipto);
1114 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD,
1115 (filter_func)check_forward);
1116 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
1117 (filter_func)check_keep_state);
1118 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
1119 (filter_func)check_check_state);
1121 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1122 O_BASIC_IN, (filter_func)check_in);
1123 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1124 O_BASIC_OUT, (filter_func)check_out);
1125 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1126 O_BASIC_VIA, (filter_func)check_via);
1127 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1128 O_BASIC_XMIT, (filter_func)check_via);
1129 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1130 O_BASIC_RECV, (filter_func)check_via);
1132 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1133 O_BASIC_PROTO, (filter_func)check_proto);
1134 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1135 O_BASIC_PROB, (filter_func)check_prob);
1136 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1137 O_BASIC_IP_SRC, (filter_func)check_from);
1138 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1139 O_BASIC_IP_SRC_LOOKUP, (filter_func)check_from_lookup);
1140 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1141 O_BASIC_IP_SRC_ME, (filter_func)check_from_me);
1142 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1143 O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask);
1144 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1145 O_BASIC_IP_DST, (filter_func)check_to);
1146 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1147 O_BASIC_IP_DST_LOOKUP, (filter_func)check_to_lookup);
1148 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1149 O_BASIC_IP_DST_ME, (filter_func)check_to_me);
1150 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1151 O_BASIC_IP_DST_MASK, (filter_func)check_to_mask);
1152 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1153 O_BASIC_TAG, (filter_func)check_tag);
1154 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1155 O_BASIC_UNTAG, (filter_func)check_untag);
1156 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1157 O_BASIC_TAGGED, (filter_func)check_tagged);
1158 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1159 O_BASIC_IP_SRCPORT, (filter_func)check_src_port);
1160 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1161 O_BASIC_IP_DSTPORT, (filter_func)check_dst_port);
1162 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1163 O_BASIC_IP_SRC_N_PORT, (filter_func)check_src_n_port);
1164 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1165 O_BASIC_IP_DST_N_PORT, (filter_func)check_dst_n_port);
1167 int cpu;
1168 struct ipfw_context *ctx;
1170 for (cpu = 0; cpu < ncpus; cpu++) {
1171 ctx = ipfw_ctx[cpu];
1172 if (ctx != NULL) {
1173 ctx->state_ctx = kmalloc(state_hash_size *
1174 sizeof(struct ipfw_state_context),
1175 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
1176 ctx->state_hash_size = state_hash_size;
1180 struct netmsg_base smsg;
1181 netmsg_init(&smsg, NULL, &curthread->td_msgport,
1182 0, ipfw_basic_init_dispatch);
1183 lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1184 return 0;
1187 static void
1188 ipfw_basic_stop_dispatch(netmsg_t nmsg)
1190 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1191 KKASSERT(IPFW3_LOADED);
1192 int error = 0;
1193 callout_stop(&ipfw_tick_callout);
1194 netmsg_service_sync();
1195 crit_enter();
1196 lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg);
1197 crit_exit();
1198 lwkt_replymsg(&nmsg->lmsg, error);
1199 ip_fw_basic_loaded=0;
1202 static int
1203 ipfw_basic_stop(void)
1205 int cpu,i;
1206 struct ipfw_state_context *state_ctx;
1207 struct ip_fw_state *state,*the_state;
1208 struct ipfw_context *ctx;
1209 if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) {
1210 ipfw_basic_flush_state_prt = NULL;
1211 ipfw_basic_append_state_prt = NULL;
1213 for (cpu = 0; cpu < ncpus; cpu++) {
1214 ctx = ipfw_ctx[cpu];
1215 if (ctx != NULL) {
1216 for (i = 0; i < state_hash_size; i++) {
1217 state_ctx = &ctx->state_ctx[i];
1218 if (state_ctx != NULL) {
1219 state = state_ctx->state;
1220 while (state != NULL) {
1221 the_state = state;
1222 state = state->next;
1223 if (the_state ==
1224 state_ctx->last)
1225 state_ctx->last = NULL;
1227 kfree(the_state,
1228 M_IPFW3_BASIC);
1232 ctx->state_hash_size = 0;
1233 kfree(ctx->state_ctx, M_IPFW3_BASIC);
1234 ctx->state_ctx = NULL;
1237 struct netmsg_base smsg;
1238 netmsg_init(&smsg, NULL, &curthread->td_msgport,
1239 0, ipfw_basic_stop_dispatch);
1240 return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1242 return 1;
1246 static int
1247 ipfw3_basic_modevent(module_t mod, int type, void *data)
1249 int err;
1250 switch (type) {
1251 case MOD_LOAD:
1252 err = ipfw_basic_init();
1253 break;
1254 case MOD_UNLOAD:
1255 err = ipfw_basic_stop();
1256 break;
1257 default:
1258 err = 1;
1260 return err;
1263 static moduledata_t ipfw3_basic_mod = {
1264 "ipfw3_basic",
1265 ipfw3_basic_modevent,
1266 NULL
1268 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
1269 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1);
1270 MODULE_VERSION(ipfw3_basic, 1);