ipfw3: support ip:port in filter from and new filter src-port
[dragonfly.git] / sys / net / ipfw3_basic / ip_fw3_basic.c
1 /*
2  * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Bill Yuan <bycn82@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/mbuf.h>
39 #include <sys/socketvar.h>
40 #include <sys/sysctl.h>
41 #include <sys/syslog.h>
42 #include <sys/systimer.h>
43 #include <sys/thread2.h>
44 #include <sys/in_cksum.h>
45
46 #include <net/if.h>
47 #include <net/ethernet.h>
48 #include <net/netmsg2.h>
49 #include <net/netisr2.h>
50 #include <net/route.h>
51
52 #include <netinet/ip.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/in_var.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/ip_var.h>
58 #include <netinet/ip_icmp.h>
59 #include <netinet/tcp.h>
60 #include <netinet/tcp_timer.h>
61 #include <netinet/tcp_var.h>
62 #include <netinet/tcpip.h>
63 #include <netinet/udp.h>
64 #include <netinet/udp_var.h>
65 #include <netinet/ip_divert.h>
66 #include <netinet/if_ether.h>
67
68 #include <net/ipfw3/ip_fw.h>
69 #include <net/ipfw3/ip_fw3_table.h>
70
71 #include "ip_fw3_basic.h"
72
73 #define TIME_LEQ(a, b)  ((int)((a) - (b)) <= 0)
74
75 extern struct ipfw_context      *ipfw_ctx[MAXCPU];
76 extern int fw_verbose;
77 extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt;
78 extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt;
79
80 static int ip_fw_basic_loaded;
81 static struct netmsg_base ipfw_timeout_netmsg;  /* schedule ipfw timeout */
82 static struct callout ipfw_tick_callout;
83 static int state_lifetime = 20;
84 static int state_expiry_check_interval = 10;
85 static int state_count_max = 4096;
86 static int state_hash_size_old = 0;
87 static int state_hash_size = 4096;
88
89
90 static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS);
91 void adjust_hash_size_dispatch(netmsg_t nmsg);
92
93 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic,
94                 CTLFLAG_RW, 0, "Firewall Basic");
95 SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size,
96                 CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0,
97                 ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size");
98
99 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW,
100                 &state_lifetime, 0, "default life time");
101 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO,
102                 state_expiry_check_interval, CTLFLAG_RW,
103                 &state_expiry_check_interval, 0,
104                 "default state expiry check interval");
105 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW,
106                 &state_count_max, 0, "maximum of state");
107
108 static int
109 ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS)
110 {
111         int error, value = 0;
112
113         state_hash_size_old = state_hash_size;
114         value = state_hash_size;
115         error = sysctl_handle_int(oidp, &value, 0, req);
116         if (error || !req->newptr) {
117                 goto back;
118         }
119         /*
120          * Make sure we have a power of 2 and
121          * do not allow more than 64k entries.
122          */
123         error = EINVAL;
124         if (value <= 1 || value > 65536) {
125                 goto back;
126         }
127         if ((value & (value - 1)) != 0) {
128                 goto back;
129         }
130
131         error = 0;
132         if (state_hash_size != value) {
133                 state_hash_size = value;
134
135                 struct netmsg_base *msg, the_msg;
136                 msg = &the_msg;
137                 bzero(msg,sizeof(struct netmsg_base));
138
139                 netmsg_init(msg, NULL, &curthread->td_msgport,
140                                 0, adjust_hash_size_dispatch);
141                 ifnet_domsg(&msg->lmsg, 0);
142         }
143 back:
144         return error;
145 }
146
147 void
148 adjust_hash_size_dispatch(netmsg_t nmsg)
149 {
150         struct ipfw_state_context *state_ctx;
151         struct ip_fw_state *the_state, *state;
152         struct ipfw_context *ctx = ipfw_ctx[mycpuid];
153         int i;
154
155         for (i = 0; i < state_hash_size_old; i++) {
156                 state_ctx = &ctx->state_ctx[i];
157                 if (state_ctx != NULL) {
158                         state = state_ctx->state;
159                         while (state != NULL) {
160                                 the_state = state;
161                                 state = state->next;
162                                 kfree(the_state, M_IPFW3_BASIC);
163                                 the_state = NULL;
164                         }
165                 }
166         }
167         kfree(ctx->state_ctx,M_IPFW3_BASIC);
168         ctx->state_ctx = kmalloc(state_hash_size *
169                                 sizeof(struct ipfw_state_context),
170                                 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
171         ctx->state_hash_size = state_hash_size;
172         ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
173 }
174
175
176 /*      prototype of the checker functions      */
177 void check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
178         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
179 void check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
180         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
181 void check_forward(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_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
184         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
185
186 void check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
187         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
188 void check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
189         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
190 void check_via(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_proto(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_prob(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_from(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_from_lookup(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_me(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_mask(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_to(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_to_lookup(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_me(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_mask(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_keep_state(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_tag(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_untag(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_tagged(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_src_port(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_dst_port(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_n_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_n_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
229 /*      prototype of the utility functions      */
230 static struct ip_fw *lookup_next_rule(struct ip_fw *me);
231 static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd);
232 static __inline int hash_packet(struct ipfw_flow_id *id);
233
234 static __inline int
235 hash_packet(struct ipfw_flow_id *id)
236 {
237         uint32_t i;
238         i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^
239                 (id->dst_port) ^ (id->src_port);
240         i &= state_hash_size - 1;
241         return i;
242 }
243
244 static struct ip_fw *
245 lookup_next_rule(struct ip_fw *me)
246 {
247         struct ip_fw *rule = NULL;
248         ipfw_insn *cmd;
249
250         /* look for action, in case it is a skipto */
251         cmd = ACTION_PTR(me);
252         if ((int)cmd->module == MODULE_BASIC_ID &&
253                 (int)cmd->opcode == O_BASIC_SKIPTO) {
254                 for (rule = me->next; rule; rule = rule->next) {
255                         if (rule->rulenum >= cmd->arg1)
256                                 break;
257                 }
258         }
259         if (rule == NULL) /* failure or not a skipto */
260                 rule = me->next;
261
262         me->next_rule = rule;
263         return rule;
264 }
265
266 /*
267  * when all = 1, it will check all the state_ctx
268  */
269 static struct ip_fw_state *
270 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all)
271 {
272         struct ip_fw_state *state = NULL;
273         struct ipfw_context *ctx = ipfw_ctx[mycpuid];
274         struct ipfw_state_context *state_ctx;
275         int start, end, i, count = 0;
276
277         if (all && cmd->arg1) {
278                 start = 0;
279                 end = state_hash_size - 1;
280         } else {
281                 start = hash_packet(&args->f_id);
282                 end = hash_packet(&args->f_id);
283         }
284         for (i = start; i <= end; i++) {
285                 state_ctx = &ctx->state_ctx[i];
286                 if (state_ctx != NULL) {
287                         state = state_ctx->state;
288                         struct ipfw_flow_id     *fid = &args->f_id;
289                         while (state != NULL) {
290                                 if (cmd->arg1) {
291                                         if ((cmd->arg3 == 1 &&
292                                                 fid->src_ip ==
293                                                 state->flow_id.src_ip) ||
294                                                 (cmd->arg3 == 2 &&
295                                                 fid->src_port ==
296                                                 state->flow_id.src_port) ||
297                                                 (cmd->arg3 == 3 &&
298                                                 fid->dst_ip ==
299                                                 state->flow_id.dst_ip) ||
300                                                 (cmd->arg3 == 4 &&
301                                                 fid->dst_port ==
302                                                 state->flow_id.dst_port)) {
303
304                                                 count++;
305                                                 if (count >= cmd->arg1) {
306                                                         *limited = 1;
307                                                         goto done;
308                                                 }
309                                         }
310                                 }
311
312                                 if (fid->proto == state->flow_id.proto) {
313                                         if (fid->src_ip ==
314                                         state->flow_id.src_ip &&
315                                         fid->dst_ip ==
316                                         state->flow_id.dst_ip &&
317                                         (fid->src_port ==
318                                         state->flow_id.src_port ||
319                                         state->flow_id.src_port == 0) &&
320                                         (fid->dst_port ==
321                                         state->flow_id.dst_port ||
322                                         state->flow_id.dst_port == 0)) {
323                                                 goto done;
324                                         }
325                                         if (fid->src_ip ==
326                                         state->flow_id.dst_ip &&
327                                         fid->dst_ip ==
328                                         state->flow_id.src_ip &&
329                                         (fid->src_port ==
330                                         state->flow_id.dst_port ||
331                                         state->flow_id.dst_port == 0) &&
332                                         (fid->dst_port ==
333                                         state->flow_id.src_port ||
334                                         state->flow_id.src_port == 0)) {
335                                                 goto done;
336                                         }
337                                 }
338                                 state = state->next;
339                         }
340                 }
341         }
342 done:
343         return state;
344 }
345
346 static struct ip_fw_state *
347 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args)
348 {
349         struct ip_fw_state *state;
350         struct ipfw_context *ctx = ipfw_ctx[mycpuid];
351         struct ipfw_state_context *state_ctx;
352         state_ctx = &ctx->state_ctx[hash_packet(&args->f_id)];
353         state = kmalloc(sizeof(struct ip_fw_state),
354                         M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
355         if (state == NULL) {
356                 return NULL;
357         }
358         state->stub = rule;
359         state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ;
360         state->timestamp = time_second;
361         state->expiry = 0;
362         bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id));
363         //append the state into the state chian
364         if (state_ctx->last != NULL)
365                 state_ctx->last->next = state;
366         else
367                 state_ctx->state = state;
368         state_ctx->last = state;
369         state_ctx->count++;
370         return state;
371 }
372
373
374 static int
375 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
376 {
377         if (ifp == NULL)        /* no iface with this packet, match fails */
378                 return 0;
379
380         /* Check by name or by IP address */
381         if (cmd->name[0] != '\0') { /* match by name */
382                 /* Check name */
383                 if (cmd->p.glob) {
384                         if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
385                                 return(1);
386                 } else {
387                         if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
388                                 return(1);
389                 }
390         } else {
391                 struct ifaddr_container *ifac;
392
393                 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
394                         struct ifaddr *ia = ifac->ifa;
395
396                         if (ia->ifa_addr == NULL)
397                                 continue;
398                         if (ia->ifa_addr->sa_family != AF_INET)
399                                 continue;
400                         if (cmd->p.ip.s_addr ==
401                                 ((struct sockaddr_in *)
402                                 (ia->ifa_addr))->sin_addr.s_addr)
403                                         return(1);      /* match */
404
405                 }
406         }
407         return 0;       /* no match, fail ... */
408 }
409
410 /* implimentation of the checker functions */
411 void
412 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
413         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
414 {
415         (*f)->pcnt++;
416         (*f)->bcnt += ip_len;
417         (*f)->timestamp = time_second;
418         *cmd_ctl = IP_FW_CTL_NEXT;
419 }
420
421 void
422 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
423         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
424 {
425         (*f)->pcnt++;
426         (*f)->bcnt += ip_len;
427         (*f)->timestamp = time_second;
428         if ((*f)->next_rule == NULL)
429                 lookup_next_rule(*f);
430
431         *cmd_ctl = IP_FW_CTL_AGAIN;
432 }
433
434 void
435 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
436         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
437 {
438         struct sockaddr_in *sin, *sa;
439         struct m_tag *mtag;
440
441         if ((*args)->eh) {      /* not valid on layer2 pkts */
442                 *cmd_ctl=IP_FW_CTL_NEXT;
443                 return;
444         }
445
446         (*f)->pcnt++;
447         (*f)->bcnt += ip_len;
448         (*f)->timestamp = time_second;
449         if ((*f)->next_rule == NULL)
450                 lookup_next_rule(*f);
451
452         mtag = m_tag_get(PACKET_TAG_IPFORWARD,
453                         sizeof(*sin), M_NOWAIT);
454         if (mtag == NULL) {
455                 *cmd_val = IP_FW_DENY;
456                 *cmd_ctl = IP_FW_CTL_DONE;
457                 return;
458         }
459         sin = m_tag_data(mtag);
460         sa = &((ipfw_insn_sa *)cmd)->sa;
461         /* arg3: count of the dest, arg1: type of fwd */
462         int i = 0;
463         if(cmd->arg3 > 1) {
464                 if (cmd->arg1 == 0) {           /* type: random */
465                         i = krandom() % cmd->arg3;
466                 } else if (cmd->arg1 == 1) {    /* type: round-robin */
467                         i = cmd->arg2++ % cmd->arg3;
468                 } else if (cmd->arg1 == 2) {    /* type: sticky */
469                         struct ip *ip = mtod((*args)->m, struct ip *);
470                         i = ip->ip_src.s_addr & (cmd->arg3 - 1);
471                 }
472                 sa += i;
473         }
474         *sin = *sa;     /* apply the destination */
475         m_tag_prepend((*args)->m, mtag);
476         (*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED;
477         (*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
478         *cmd_ctl = IP_FW_CTL_DONE;
479         *cmd_val = IP_FW_PASS;
480 }
481
482 void
483 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
484         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
485 {
486         struct ip_fw_state *state=NULL;
487         int limited = 0 ;
488         state = lookup_state(*args, cmd, &limited, 0);
489         if (state != NULL) {
490                 state->pcnt++;
491                 state->bcnt += ip_len;
492                 state->timestamp = time_second;
493                 (*f)->pcnt++;
494                 (*f)->bcnt += ip_len;
495                 (*f)->timestamp = time_second;
496                 *f = state->stub;
497                 *cmd_ctl = IP_FW_CTL_CHK_STATE;
498         } else {
499                 *cmd_ctl = IP_FW_CTL_NEXT;
500         }
501 }
502
503 void
504 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
505         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
506 {
507         *cmd_ctl = IP_FW_CTL_NO;
508         *cmd_val = ((*args)->oif == NULL);
509 }
510
511 void
512 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
513         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
514 {
515         *cmd_ctl = IP_FW_CTL_NO;
516         *cmd_val = ((*args)->oif != NULL);
517 }
518
519 void
520 check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
521         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
522 {
523         *cmd_ctl = IP_FW_CTL_NO;
524         *cmd_val = iface_match((*args)->oif ?
525                         (*args)->oif : (*args)->m->m_pkthdr.rcvif,
526                         (ipfw_insn_if *)cmd);
527 }
528
529 void
530 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
531         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
532 {
533         *cmd_ctl = IP_FW_CTL_NO;
534         *cmd_val = ((*args)->f_id.proto == cmd->arg1);
535 }
536
537 void
538 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
539         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
540 {
541         *cmd_ctl = IP_FW_CTL_NO;
542         *cmd_val = (krandom() % 100) < cmd->arg1;
543 }
544
545 void
546 check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
547         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
548 {
549         struct in_addr src_ip;
550         u_int hlen = 0;
551         struct mbuf *m = (*args)->m;
552         struct ip *ip = mtod(m, struct ip *);
553         src_ip = ip->ip_src;
554         if ((*args)->eh == NULL ||
555                 (m->m_pkthdr.len >= sizeof(struct ip) &&
556                 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
557                 hlen = ip->ip_hl << 2;
558         }
559         *cmd_val = (hlen > 0 &&
560                         ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
561         *cmd_ctl = IP_FW_CTL_NO;
562 }
563
564 void
565 check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
566         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
567 {
568         struct ipfw_context *ctx = ipfw_ctx[mycpuid];
569         struct ipfw_table_context *table_ctx;
570         struct radix_node_head *rnh;
571         struct sockaddr_in sa;
572
573         struct mbuf *m = (*args)->m;
574         struct ip *ip = mtod(m, struct ip *);
575         struct in_addr src_ip = ip->ip_src;
576
577         *cmd_val = IP_FW_NOT_MATCH;
578
579         table_ctx = ctx->table_ctx;
580         table_ctx += cmd->arg1;
581
582         if (table_ctx->type != 0) {
583                 rnh = table_ctx->node;
584                 sa.sin_len = 8;
585                 sa.sin_addr.s_addr = src_ip.s_addr;
586                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
587                         *cmd_val = IP_FW_MATCH;
588         }
589         *cmd_ctl = IP_FW_CTL_NO;
590 }
591
592 void
593 check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
594         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
595 {
596         struct in_addr src_ip;
597         u_int hlen = 0;
598         struct mbuf *m = (*args)->m;
599         struct ip *ip = mtod(m, struct ip *);
600         src_ip = ip->ip_src;
601         if ((*args)->eh == NULL ||
602                 (m->m_pkthdr.len >= sizeof(struct ip) &&
603                 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
604                 hlen = ip->ip_hl << 2;
605         }
606         *cmd_ctl = IP_FW_CTL_NO;
607         if (hlen > 0) {
608                 struct ifnet *tif;
609                 tif = INADDR_TO_IFP(&src_ip);
610                 *cmd_val = (tif != NULL);
611         } else {
612                 *cmd_val = IP_FW_NOT_MATCH;
613         }
614 }
615
616 void
617 check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
618         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
619 {
620         struct in_addr src_ip;
621         u_int hlen = 0;
622         struct mbuf *m = (*args)->m;
623         struct ip *ip = mtod(m, struct ip *);
624         src_ip = ip->ip_src;
625         if ((*args)->eh == NULL ||
626                 (m->m_pkthdr.len >= sizeof(struct ip) &&
627                 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
628                 hlen = ip->ip_hl << 2;
629         }
630
631         *cmd_ctl = IP_FW_CTL_NO;
632         *cmd_val = (hlen > 0 &&
633                         ((ipfw_insn_ip *)cmd)->addr.s_addr ==
634                         (src_ip.s_addr &
635                         ((ipfw_insn_ip *)cmd)->mask.s_addr));
636 }
637
638 void
639 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
640         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
641 {
642         struct in_addr dst_ip;
643         u_int hlen = 0;
644         struct mbuf *m = (*args)->m;
645         struct ip *ip = mtod(m, struct ip *);
646         dst_ip = ip->ip_dst;
647         if ((*args)->eh == NULL ||
648                 (m->m_pkthdr.len >= sizeof(struct ip) &&
649                  ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
650                 hlen = ip->ip_hl << 2;
651         }
652         *cmd_val = (hlen > 0 &&
653                         ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
654         *cmd_ctl = IP_FW_CTL_NO;
655 }
656
657 void
658 check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
659         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
660 {
661         struct ipfw_context *ctx = ipfw_ctx[mycpuid];
662         struct ipfw_table_context *table_ctx;
663         struct radix_node_head *rnh;
664         struct sockaddr_in sa;
665
666         struct mbuf *m = (*args)->m;
667         struct ip *ip = mtod(m, struct ip *);
668         struct in_addr dst_ip = ip->ip_dst;
669
670         *cmd_val = IP_FW_NOT_MATCH;
671
672         table_ctx = ctx->table_ctx;
673         table_ctx += cmd->arg1;
674
675         if (table_ctx->type != 0) {
676                 rnh = table_ctx->node;
677                 sa.sin_len = 8;
678                 sa.sin_addr.s_addr = dst_ip.s_addr;
679                 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
680                         *cmd_val = IP_FW_MATCH;
681         }
682         *cmd_ctl = IP_FW_CTL_NO;
683 }
684
685 void
686 check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
687         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
688 {
689         struct in_addr dst_ip;
690         u_int hlen = 0;
691         struct mbuf *m = (*args)->m;
692         struct ip *ip = mtod(m, struct ip *);
693         dst_ip = ip->ip_src;
694         if ((*args)->eh == NULL ||
695                 (m->m_pkthdr.len >= sizeof(struct ip) &&
696                 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
697                 hlen = ip->ip_hl << 2;
698         }
699         *cmd_ctl = IP_FW_CTL_NO;
700         if (hlen > 0) {
701                 struct ifnet *tif;
702                 tif = INADDR_TO_IFP(&dst_ip);
703                 *cmd_val = (tif != NULL);
704         } else {
705                 *cmd_val = IP_FW_NOT_MATCH;
706         }
707 }
708
709 void
710 check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
711         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
712 {
713         struct in_addr dst_ip;
714         u_int hlen = 0;
715         struct mbuf *m = (*args)->m;
716         struct ip *ip = mtod(m, struct ip *);
717         dst_ip = ip->ip_src;
718         if ((*args)->eh == NULL ||
719                 (m->m_pkthdr.len >= sizeof(struct ip) &&
720                 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
721                 hlen = ip->ip_hl << 2;
722         }
723
724         *cmd_ctl = IP_FW_CTL_NO;
725         *cmd_val = (hlen > 0 &&
726                         ((ipfw_insn_ip *)cmd)->addr.s_addr ==
727                         (dst_ip.s_addr &
728                         ((ipfw_insn_ip *)cmd)->mask.s_addr));
729 }
730
731 void
732 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
733         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
734 {
735         struct ip_fw_state *state;
736         int limited = 0;
737
738         *cmd_ctl = IP_FW_CTL_NO;
739         state = lookup_state(*args, cmd, &limited, 1);
740         if (limited == 1) {
741                 *cmd_val = IP_FW_NOT_MATCH;
742         } else {
743                 if (state == NULL)
744                         state = install_state(*f, cmd, *args);
745
746                 if (state != NULL) {
747                         state->pcnt++;
748                         state->bcnt += ip_len;
749                         state->timestamp = time_second;
750                         *cmd_val = IP_FW_MATCH;
751                 } else {
752                         *cmd_val = IP_FW_NOT_MATCH;
753                 }
754         }
755 }
756
757 void
758 check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
759         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
760 {
761         struct m_tag *mtag = m_tag_locate((*args)->m,
762                         MTAG_IPFW, cmd->arg1, NULL);
763         if (mtag == NULL) {
764                 mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT);
765                 if (mtag != NULL)
766                         m_tag_prepend((*args)->m, mtag);
767
768         }
769         (*f)->pcnt++;
770         (*f)->bcnt += ip_len;
771         (*f)->timestamp = time_second;
772         *cmd_ctl = IP_FW_CTL_NEXT;
773 }
774
775 void
776 check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
777         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
778 {
779         struct m_tag *mtag = m_tag_locate((*args)->m,
780                         MTAG_IPFW, cmd->arg1, NULL);
781         if (mtag != NULL)
782                 m_tag_delete((*args)->m, mtag);
783
784         (*f)->pcnt++;
785         (*f)->bcnt += ip_len;
786         (*f)->timestamp = time_second;
787         *cmd_ctl = IP_FW_CTL_NEXT;
788 }
789
790 void
791 check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
792         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
793 {
794         *cmd_ctl = IP_FW_CTL_NO;
795         if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL )
796                 *cmd_val = IP_FW_MATCH;
797         else
798                 *cmd_val = IP_FW_NOT_MATCH;
799 }
800
801 void
802 check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
803         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
804 {
805         *cmd_ctl = IP_FW_CTL_NO;
806         if ((*args)->f_id.src_port == cmd->arg1)
807                 *cmd_val = IP_FW_MATCH;
808         else
809                 *cmd_val = IP_FW_NOT_MATCH;
810 }
811
812 void
813 check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
814         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
815 {
816         *cmd_ctl = IP_FW_CTL_NO;
817         if ((*args)->f_id.dst_port == cmd->arg1)
818                 *cmd_val = IP_FW_MATCH;
819         else
820                 *cmd_val = IP_FW_NOT_MATCH;
821 }
822
823 void
824 check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
825         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
826 {
827         struct in_addr src_ip;
828         u_int hlen = 0;
829         struct mbuf *m = (*args)->m;
830         struct ip *ip = mtod(m, struct ip *);
831         src_ip = ip->ip_src;
832         if ((*args)->eh == NULL ||
833                 (m->m_pkthdr.len >= sizeof(struct ip) &&
834                 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
835                 hlen = ip->ip_hl << 2;
836         }
837         *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
838         *cmd_ctl = IP_FW_CTL_NO;
839         if (*cmd_val && (*args)->f_id.src_port == cmd->arg1)
840                 *cmd_val = IP_FW_MATCH;
841         else
842                 *cmd_val = IP_FW_NOT_MATCH;
843 }
844
845 void
846 check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
847         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
848 {
849         struct in_addr dst_ip;
850         u_int hlen = 0;
851         struct mbuf *m = (*args)->m;
852         struct ip *ip = mtod(m, struct ip *);
853         dst_ip = ip->ip_dst;
854         if ((*args)->eh == NULL ||
855                 (m->m_pkthdr.len >= sizeof(struct ip) &&
856                  ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
857                 hlen = ip->ip_hl << 2;
858         }
859         *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
860         *cmd_ctl = IP_FW_CTL_NO;
861         if (*cmd_val && (*args)->f_id.dst_port == cmd->arg1)
862                 *cmd_val = IP_FW_MATCH;
863         else
864                 *cmd_val = IP_FW_NOT_MATCH;
865 }
866
867
868
869 static void
870 ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state)
871 {
872         struct ip_fw_state *state;
873         struct ipfw_context *ctx = ipfw_ctx[mycpuid];
874         struct ipfw_state_context *state_ctx;
875         state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))];
876         state = kmalloc(sizeof(struct ip_fw_state),
877                         M_IPFW3_BASIC, M_WAITOK | M_ZERO);
878         struct ip_fw *rule = ctx->ipfw_rule_chain;
879         while (rule != NULL) {
880                 if (rule->rulenum == ioc_state->rulenum) {
881                         break;
882                 }
883                 rule = rule->next;
884         }
885         if (rule == NULL)
886                 return;
887
888         state->stub = rule;
889
890         state->lifetime = ioc_state->lifetime == 0 ?
891                 state_lifetime : ioc_state->lifetime ;
892         state->timestamp = time_second;
893         state->expiry = ioc_state->expiry;
894         bcopy(&ioc_state->flow_id, &state->flow_id,
895                         sizeof(struct ipfw_flow_id));
896         //append the state into the state chian
897         if (state_ctx->last != NULL)
898                 state_ctx->last->next = state;
899         else
900                 state_ctx->state = state;
901
902         state_ctx->last = state;
903         state_ctx->count++;
904 }
905
906 /*
907  * if rule is NULL
908  *              flush all states
909  * else
910  *              flush states which stub is the rule
911  */
912 static void
913 ipfw_basic_flush_state(struct ip_fw *rule)
914 {
915         struct ipfw_state_context *state_ctx;
916         struct ip_fw_state *state,*the_state, *prev_state;
917         struct ipfw_context *ctx;
918         int i;
919
920         ctx = ipfw_ctx[mycpuid];
921         for (i = 0; i < state_hash_size; i++) {
922                 state_ctx = &ctx->state_ctx[i];
923                 if (state_ctx != NULL) {
924                         state = state_ctx->state;
925                         prev_state = NULL;
926                         while (state != NULL) {
927                                 if (rule != NULL && state->stub != rule) {
928                                         prev_state = state;
929                                         state = state->next;
930                                 } else {
931                                         if (prev_state == NULL)
932                                                 state_ctx->state = state->next;
933                                         else
934                                                 prev_state->next = state->next;
935
936                                         the_state = state;
937                                         state = state->next;
938                                         kfree(the_state, M_IPFW3_BASIC);
939                                         state_ctx->count--;
940                                         if (state == NULL)
941                                                 state_ctx->last = prev_state;
942
943                                 }
944                         }
945                 }
946         }
947 }
948
949 /*
950  * clean up expired state in every tick
951  */
952 static void
953 ipfw_cleanup_expired_state(netmsg_t nmsg)
954 {
955         struct ip_fw_state *state,*the_state,*prev_state;
956         struct ipfw_context *ctx = ipfw_ctx[mycpuid];
957         struct ipfw_state_context *state_ctx;
958         int i;
959
960         for (i = 0; i < state_hash_size; i++) {
961                 prev_state = NULL;
962                 state_ctx = &(ctx->state_ctx[i]);
963                 if (ctx->state_ctx != NULL) {
964                         state = state_ctx->state;
965                         while (state != NULL) {
966                                 if (IS_EXPIRED(state)) {
967                                         if (prev_state == NULL)
968                                                 state_ctx->state = state->next;
969                                         else
970                                                 prev_state->next = state->next;
971
972                                         the_state =state;
973                                         state = state->next;
974
975                                         if (the_state == state_ctx->last)
976                                                 state_ctx->last = NULL;
977
978
979                                         kfree(the_state, M_IPFW3_BASIC);
980                                         state_ctx->count--;
981                                 } else {
982                                         prev_state = state;
983                                         state = state->next;
984                                 }
985                         }
986                 }
987         }
988         ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
989 }
990
991 static void
992 ipfw_tick(void *dummy __unused)
993 {
994         struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg;
995         KKASSERT(mycpuid == IPFW_CFGCPUID);
996
997         crit_enter();
998         KKASSERT(lmsg->ms_flags & MSGF_DONE);
999         if (IPFW_BASIC_LOADED) {
1000                 lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg);
1001                 /* ipfw_timeout_netmsg's handler reset this callout */
1002         }
1003         crit_exit();
1004
1005         struct netmsg_base *msg;
1006         struct netmsg_base the_msg;
1007         msg = &the_msg;
1008         bzero(msg,sizeof(struct netmsg_base));
1009
1010         netmsg_init(msg, NULL, &curthread->td_msgport, 0,
1011                         ipfw_cleanup_expired_state);
1012         ifnet_domsg(&msg->lmsg, 0);
1013 }
1014
1015 static void
1016 ipfw_tick_dispatch(netmsg_t nmsg)
1017 {
1018         IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1019         KKASSERT(IPFW_BASIC_LOADED);
1020
1021         /* Reply ASAP */
1022         crit_enter();
1023         lwkt_replymsg(&nmsg->lmsg, 0);
1024         crit_exit();
1025
1026         callout_reset(&ipfw_tick_callout,
1027                         state_expiry_check_interval * hz, ipfw_tick, NULL);
1028 }
1029
1030 static void
1031 ipfw_basic_init_dispatch(netmsg_t nmsg)
1032 {
1033         IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1034         KKASSERT(IPFW3_LOADED);
1035
1036         int error = 0;
1037         callout_init_mp(&ipfw_tick_callout);
1038         netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport,
1039                         MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch);
1040         callout_reset(&ipfw_tick_callout,
1041                         state_expiry_check_interval * hz, ipfw_tick, NULL);
1042         lwkt_replymsg(&nmsg->lmsg, error);
1043         ip_fw_basic_loaded=1;
1044 }
1045
1046 static int
1047 ipfw_basic_init(void)
1048 {
1049         ipfw_basic_flush_state_prt = ipfw_basic_flush_state;
1050         ipfw_basic_append_state_prt = ipfw_basic_add_state;
1051
1052         register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME);
1053         register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT,
1054                         (filter_func)check_count);
1055         register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO,
1056                         (filter_func)check_skipto);
1057         register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD,
1058                         (filter_func)check_forward);
1059         register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
1060                         (filter_func)check_keep_state);
1061         register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
1062                         (filter_func)check_check_state);
1063
1064         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1065                         O_BASIC_IN, (filter_func)check_in);
1066         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1067                         O_BASIC_OUT, (filter_func)check_out);
1068         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1069                         O_BASIC_VIA, (filter_func)check_via);
1070         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1071                         O_BASIC_XMIT, (filter_func)check_via);
1072         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1073                         O_BASIC_RECV, (filter_func)check_via);
1074
1075         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1076                         O_BASIC_PROTO, (filter_func)check_proto);
1077         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1078                         O_BASIC_PROB, (filter_func)check_prob);
1079         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1080                         O_BASIC_IP_SRC, (filter_func)check_from);
1081         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1082                         O_BASIC_IP_SRC_LOOKUP, (filter_func)check_from_lookup);
1083         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1084                         O_BASIC_IP_SRC_ME, (filter_func)check_from_me);
1085         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1086                         O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask);
1087         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1088                         O_BASIC_IP_DST, (filter_func)check_to);
1089         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1090                         O_BASIC_IP_DST_LOOKUP, (filter_func)check_to_lookup);
1091         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1092                         O_BASIC_IP_DST_ME, (filter_func)check_to_me);
1093         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1094                         O_BASIC_IP_DST_MASK, (filter_func)check_to_mask);
1095         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1096                         O_BASIC_TAG, (filter_func)check_tag);
1097         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1098                         O_BASIC_UNTAG, (filter_func)check_untag);
1099         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1100                         O_BASIC_TAGGED, (filter_func)check_tagged);
1101         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1102                         O_BASIC_IP_SRCPORT, (filter_func)check_src_port);
1103         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1104                         O_BASIC_IP_DSTPORT, (filter_func)check_dst_port);
1105         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1106                         O_BASIC_IP_SRC_N_PORT, (filter_func)check_src_n_port);
1107         register_ipfw_filter_funcs(MODULE_BASIC_ID,
1108                         O_BASIC_IP_DST_N_PORT, (filter_func)check_dst_n_port);
1109
1110         int cpu;
1111         struct ipfw_context *ctx;
1112
1113         for (cpu = 0; cpu < ncpus; cpu++) {
1114                 ctx = ipfw_ctx[cpu];
1115                 if (ctx != NULL) {
1116                         ctx->state_ctx = kmalloc(state_hash_size *
1117                                         sizeof(struct ipfw_state_context),
1118                                         M_IPFW3_BASIC, M_WAITOK | M_ZERO);
1119                         ctx->state_hash_size = state_hash_size;
1120                 }
1121         }
1122
1123         struct netmsg_base smsg;
1124         netmsg_init(&smsg, NULL, &curthread->td_msgport,
1125                         0, ipfw_basic_init_dispatch);
1126         lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1127         return 0;
1128 }
1129
1130 static void
1131 ipfw_basic_stop_dispatch(netmsg_t nmsg)
1132 {
1133         IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1134         KKASSERT(IPFW3_LOADED);
1135         int error = 0;
1136         callout_stop(&ipfw_tick_callout);
1137         netmsg_service_sync();
1138         crit_enter();
1139         lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg);
1140         crit_exit();
1141         lwkt_replymsg(&nmsg->lmsg, error);
1142         ip_fw_basic_loaded=0;
1143 }
1144
1145 static int
1146 ipfw_basic_stop(void)
1147 {
1148         int cpu,i;
1149         struct ipfw_state_context *state_ctx;
1150         struct ip_fw_state *state,*the_state;
1151         struct ipfw_context *ctx;
1152         if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) {
1153                 ipfw_basic_flush_state_prt = NULL;
1154                 ipfw_basic_append_state_prt = NULL;
1155
1156                 for (cpu = 0; cpu < ncpus; cpu++) {
1157                         ctx = ipfw_ctx[cpu];
1158                         if (ctx != NULL) {
1159                                 for (i = 0; i < state_hash_size; i++) {
1160                                         state_ctx = &ctx->state_ctx[i];
1161                                         if (state_ctx != NULL) {
1162                                                 state = state_ctx->state;
1163                                                 while (state != NULL) {
1164                                                         the_state = state;
1165                                                         state = state->next;
1166                                                         if (the_state ==
1167                                                                 state_ctx->last)
1168                                                         state_ctx->last = NULL;
1169
1170                                                         kfree(the_state,
1171                                                                 M_IPFW3_BASIC);
1172                                                 }
1173                                         }
1174                                 }
1175                                 ctx->state_hash_size = 0;
1176                                 kfree(ctx->state_ctx, M_IPFW3_BASIC);
1177                                 ctx->state_ctx = NULL;
1178                         }
1179                 }
1180                 struct netmsg_base smsg;
1181                 netmsg_init(&smsg, NULL, &curthread->td_msgport,
1182                                 0, ipfw_basic_stop_dispatch);
1183                 return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1184         }
1185         return 1;
1186 }
1187
1188
1189 static int
1190 ipfw3_basic_modevent(module_t mod, int type, void *data)
1191 {
1192         int err;
1193         switch (type) {
1194                 case MOD_LOAD:
1195                         err = ipfw_basic_init();
1196                         break;
1197                 case MOD_UNLOAD:
1198                         err = ipfw_basic_stop();
1199                         break;
1200                 default:
1201                         err = 1;
1202         }
1203         return err;
1204 }
1205
1206 static moduledata_t ipfw3_basic_mod = {
1207         "ipfw3_basic",
1208         ipfw3_basic_modevent,
1209         NULL
1210 };
1211 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
1212 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1);
1213 MODULE_VERSION(ipfw3_basic, 1);