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 int match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid, 231 struct ip_fw_state *state); 232 int count_match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid, 233 struct ip_fw_state *state, int *count); 234 235 static struct ip_fw *lookup_next_rule(struct ip_fw *me); 236 static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd); 237 static __inline int hash_packet(struct ipfw_flow_id *id); 238 239 static __inline int 240 hash_packet(struct ipfw_flow_id *id) 241 { 242 uint32_t i; 243 i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^ 244 (id->dst_port) ^ (id->src_port); 245 i &= state_hash_size - 1; 246 return i; 247 } 248 249 static struct ip_fw * 250 lookup_next_rule(struct ip_fw *me) 251 { 252 struct ip_fw *rule = NULL; 253 ipfw_insn *cmd; 254 255 /* look for action, in case it is a skipto */ 256 cmd = ACTION_PTR(me); 257 if ((int)cmd->module == MODULE_BASIC_ID && 258 (int)cmd->opcode == O_BASIC_SKIPTO) { 259 for (rule = me->next; rule; rule = rule->next) { 260 if (rule->rulenum >= cmd->arg1) 261 break; 262 } 263 } 264 if (rule == NULL) /* failure or not a skipto */ 265 rule = me->next; 266 267 me->next_rule = rule; 268 return rule; 269 } 270 271 /* 272 * return value 273 * 0 : not match 1: same direction 2: reverse direction 274 */ 275 int 276 match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid, struct ip_fw_state *state) 277 { 278 if (fid->src_ip == state->flow_id.src_ip && 279 fid->dst_ip == state->flow_id.dst_ip && 280 (fid->src_port == state->flow_id.src_port || 281 state->flow_id.src_port == 0) && 282 (fid->dst_port == state->flow_id.dst_port || 283 state->flow_id.dst_port == 0)) { 284 return 1; 285 } 286 if (fid->src_ip == state->flow_id.dst_ip && 287 fid->dst_ip == state->flow_id.src_ip && 288 (fid->src_port == state->flow_id.dst_port || 289 state->flow_id.dst_port == 0) && 290 (fid->dst_port == state->flow_id.src_port || 291 state->flow_id.src_port == 0)) { 292 return 2; 293 } 294 return 0; 295 } 296 297 /* 298 * return 1 when more states than limit 299 * arg3: limit type (1=src ip, 2=src port, 3=dst ip, 4=dst port) 300 * arg1: limit 301 */ 302 int 303 count_match_state(ipfw_insn *cmd, struct ipfw_flow_id *fid, 304 struct ip_fw_state *state, int *count) 305 { 306 if ((cmd->arg3 == 1 && fid->src_ip == state->flow_id.src_ip) || 307 (cmd->arg3 == 2 && fid->src_port == state->flow_id.src_port) || 308 (cmd->arg3 == 3 && fid->dst_ip == state->flow_id.dst_ip) || 309 (cmd->arg3 == 4 && fid->dst_port == state->flow_id.dst_port)) { 310 *count = *count + 1; 311 if (*count >= cmd->arg1) 312 return 1; 313 } 314 return 0; 315 } 316 317 /* 318 * when all = 1, it will check all the state_ctx 319 * all = 1 during keep-state 320 * all = 0 during check-state 321 * 322 * in the cmd of keep_state 323 * arg3=type arg1=limit 324 */ 325 static struct ip_fw_state * 326 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all) 327 { 328 struct ip_fw_state *state = NULL; 329 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 330 struct ipfw_state_context *state_ctx; 331 int start, end, i, count = 0; 332 333 if (all && cmd->arg1) { 334 start = 0; 335 end = state_hash_size - 1; 336 } else { 337 start = hash_packet(&args->f_id); 338 end = hash_packet(&args->f_id); 339 } 340 341 for (i = start; i <= end; i++) { 342 state_ctx = &ctx->state_ctx[i]; 343 if (state_ctx != NULL) { 344 state = state_ctx->state; 345 struct ipfw_flow_id *fid = &args->f_id; 346 while (state != NULL) { 347 /* has limit and already exceed the limit */ 348 if (cmd->arg1 && 349 count_match_state(cmd, fid, 350 state, &count) != 0) { 351 *limited = 1; 352 goto done; 353 } 354 355 if (fid->proto == state->flow_id.proto && 356 match_state(cmd, fid, state) != 0) 357 goto done; 358 359 state = state->next; 360 } 361 } 362 } 363 done: 364 return state; 365 } 366 367 static struct ip_fw_state * 368 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args) 369 { 370 struct ip_fw_state *state; 371 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 372 struct ipfw_state_context *state_ctx; 373 state_ctx = &ctx->state_ctx[hash_packet(&args->f_id)]; 374 state = kmalloc(sizeof(struct ip_fw_state), 375 M_IPFW3_BASIC, M_NOWAIT | M_ZERO); 376 if (state == NULL) { 377 return NULL; 378 } 379 state->stub = rule; 380 state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ; 381 state->timestamp = time_second; 382 state->expiry = 0; 383 bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id)); 384 //append the state into the state chian 385 if (state_ctx->last != NULL) 386 state_ctx->last->next = state; 387 else 388 state_ctx->state = state; 389 state_ctx->last = state; 390 state_ctx->count++; 391 return state; 392 } 393 394 395 static int 396 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd) 397 { 398 if (ifp == NULL) /* no iface with this packet, match fails */ 399 return 0; 400 401 /* Check by name or by IP address */ 402 if (cmd->name[0] != '\0') { /* match by name */ 403 /* Check name */ 404 if (cmd->p.glob) { 405 if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0) 406 return(1); 407 } else { 408 if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0) 409 return(1); 410 } 411 } else { 412 struct ifaddr_container *ifac; 413 414 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) { 415 struct ifaddr *ia = ifac->ifa; 416 417 if (ia->ifa_addr == NULL) 418 continue; 419 if (ia->ifa_addr->sa_family != AF_INET) 420 continue; 421 if (cmd->p.ip.s_addr == 422 ((struct sockaddr_in *) 423 (ia->ifa_addr))->sin_addr.s_addr) 424 return(1); /* match */ 425 426 } 427 } 428 return 0; /* no match, fail ... */ 429 } 430 431 /* implimentation of the checker functions */ 432 void 433 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 434 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 435 { 436 (*f)->pcnt++; 437 (*f)->bcnt += ip_len; 438 (*f)->timestamp = time_second; 439 *cmd_ctl = IP_FW_CTL_NEXT; 440 } 441 442 void 443 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 444 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 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 *cmd_ctl = IP_FW_CTL_AGAIN; 453 } 454 455 void 456 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 457 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 458 { 459 struct sockaddr_in *sin, *sa; 460 struct m_tag *mtag; 461 462 if ((*args)->eh) { /* not valid on layer2 pkts */ 463 *cmd_ctl=IP_FW_CTL_NEXT; 464 return; 465 } 466 467 (*f)->pcnt++; 468 (*f)->bcnt += ip_len; 469 (*f)->timestamp = time_second; 470 if ((*f)->next_rule == NULL) 471 lookup_next_rule(*f); 472 473 mtag = m_tag_get(PACKET_TAG_IPFORWARD, 474 sizeof(*sin), M_NOWAIT); 475 if (mtag == NULL) { 476 *cmd_val = IP_FW_DENY; 477 *cmd_ctl = IP_FW_CTL_DONE; 478 return; 479 } 480 sin = m_tag_data(mtag); 481 sa = &((ipfw_insn_sa *)cmd)->sa; 482 /* arg3: count of the dest, arg1: type of fwd */ 483 int i = 0; 484 if(cmd->arg3 > 1) { 485 if (cmd->arg1 == 0) { /* type: random */ 486 i = krandom() % cmd->arg3; 487 } else if (cmd->arg1 == 1) { /* type: round-robin */ 488 i = cmd->arg2++ % cmd->arg3; 489 } else if (cmd->arg1 == 2) { /* type: sticky */ 490 struct ip *ip = mtod((*args)->m, struct ip *); 491 i = ip->ip_src.s_addr & (cmd->arg3 - 1); 492 } 493 sa += i; 494 } 495 *sin = *sa; /* apply the destination */ 496 m_tag_prepend((*args)->m, mtag); 497 (*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED; 498 (*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED; 499 *cmd_ctl = IP_FW_CTL_DONE; 500 *cmd_val = IP_FW_PASS; 501 } 502 503 void 504 check_check_state(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 struct ip_fw_state *state=NULL; 508 int limited = 0 ; 509 state = lookup_state(*args, cmd, &limited, 0); 510 if (state != NULL) { 511 state->pcnt++; 512 state->bcnt += ip_len; 513 state->timestamp = time_second; 514 (*f)->pcnt++; 515 (*f)->bcnt += ip_len; 516 (*f)->timestamp = time_second; 517 *f = state->stub; 518 *cmd_ctl = IP_FW_CTL_CHK_STATE; 519 } else { 520 *cmd_ctl = IP_FW_CTL_NEXT; 521 } 522 } 523 524 void 525 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 526 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 527 { 528 *cmd_ctl = IP_FW_CTL_NO; 529 *cmd_val = ((*args)->oif == NULL); 530 } 531 532 void 533 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 534 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 535 { 536 *cmd_ctl = IP_FW_CTL_NO; 537 *cmd_val = ((*args)->oif != NULL); 538 } 539 540 void 541 check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 542 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 543 { 544 *cmd_ctl = IP_FW_CTL_NO; 545 *cmd_val = iface_match((*args)->oif ? 546 (*args)->oif : (*args)->m->m_pkthdr.rcvif, 547 (ipfw_insn_if *)cmd); 548 } 549 550 void 551 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 552 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 553 { 554 *cmd_ctl = IP_FW_CTL_NO; 555 *cmd_val = ((*args)->f_id.proto == cmd->arg1); 556 } 557 558 void 559 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 560 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 561 { 562 *cmd_ctl = IP_FW_CTL_NO; 563 *cmd_val = (krandom() % 100) < cmd->arg1; 564 } 565 566 void 567 check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 568 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 569 { 570 struct in_addr src_ip; 571 u_int hlen = 0; 572 struct mbuf *m = (*args)->m; 573 struct ip *ip = mtod(m, struct ip *); 574 src_ip = ip->ip_src; 575 if ((*args)->eh == NULL || 576 (m->m_pkthdr.len >= sizeof(struct ip) && 577 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 578 hlen = ip->ip_hl << 2; 579 } 580 *cmd_val = (hlen > 0 && 581 ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr); 582 *cmd_ctl = IP_FW_CTL_NO; 583 } 584 585 void 586 check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 587 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 588 { 589 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 590 struct ipfw_table_context *table_ctx; 591 struct radix_node_head *rnh; 592 struct sockaddr_in sa; 593 594 struct mbuf *m = (*args)->m; 595 struct ip *ip = mtod(m, struct ip *); 596 struct in_addr src_ip = ip->ip_src; 597 598 *cmd_val = IP_FW_NOT_MATCH; 599 600 table_ctx = ctx->table_ctx; 601 table_ctx += cmd->arg1; 602 603 if (table_ctx->type != 0) { 604 rnh = table_ctx->node; 605 sa.sin_len = 8; 606 sa.sin_addr.s_addr = src_ip.s_addr; 607 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL) 608 *cmd_val = IP_FW_MATCH; 609 } 610 *cmd_ctl = IP_FW_CTL_NO; 611 } 612 613 void 614 check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 615 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 616 { 617 struct in_addr src_ip; 618 u_int hlen = 0; 619 struct mbuf *m = (*args)->m; 620 struct ip *ip = mtod(m, struct ip *); 621 src_ip = ip->ip_src; 622 if ((*args)->eh == NULL || 623 (m->m_pkthdr.len >= sizeof(struct ip) && 624 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 625 hlen = ip->ip_hl << 2; 626 } 627 *cmd_ctl = IP_FW_CTL_NO; 628 if (hlen > 0) { 629 struct ifnet *tif; 630 tif = INADDR_TO_IFP(&src_ip); 631 *cmd_val = (tif != NULL); 632 } else { 633 *cmd_val = IP_FW_NOT_MATCH; 634 } 635 } 636 637 void 638 check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 639 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 640 { 641 struct in_addr src_ip; 642 u_int hlen = 0; 643 struct mbuf *m = (*args)->m; 644 struct ip *ip = mtod(m, struct ip *); 645 src_ip = ip->ip_src; 646 if ((*args)->eh == NULL || 647 (m->m_pkthdr.len >= sizeof(struct ip) && 648 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 649 hlen = ip->ip_hl << 2; 650 } 651 652 *cmd_ctl = IP_FW_CTL_NO; 653 *cmd_val = (hlen > 0 && 654 ((ipfw_insn_ip *)cmd)->addr.s_addr == 655 (src_ip.s_addr & 656 ((ipfw_insn_ip *)cmd)->mask.s_addr)); 657 } 658 659 void 660 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 661 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 662 { 663 struct in_addr dst_ip; 664 u_int hlen = 0; 665 struct mbuf *m = (*args)->m; 666 struct ip *ip = mtod(m, struct ip *); 667 dst_ip = ip->ip_dst; 668 if ((*args)->eh == NULL || 669 (m->m_pkthdr.len >= sizeof(struct ip) && 670 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 671 hlen = ip->ip_hl << 2; 672 } 673 *cmd_val = (hlen > 0 && 674 ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr); 675 *cmd_ctl = IP_FW_CTL_NO; 676 } 677 678 void 679 check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 680 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 681 { 682 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 683 struct ipfw_table_context *table_ctx; 684 struct radix_node_head *rnh; 685 struct sockaddr_in sa; 686 687 struct mbuf *m = (*args)->m; 688 struct ip *ip = mtod(m, struct ip *); 689 struct in_addr dst_ip = ip->ip_dst; 690 691 *cmd_val = IP_FW_NOT_MATCH; 692 693 table_ctx = ctx->table_ctx; 694 table_ctx += cmd->arg1; 695 696 if (table_ctx->type != 0) { 697 rnh = table_ctx->node; 698 sa.sin_len = 8; 699 sa.sin_addr.s_addr = dst_ip.s_addr; 700 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL) 701 *cmd_val = IP_FW_MATCH; 702 } 703 *cmd_ctl = IP_FW_CTL_NO; 704 } 705 706 void 707 check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 708 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 709 { 710 struct in_addr dst_ip; 711 u_int hlen = 0; 712 struct mbuf *m = (*args)->m; 713 struct ip *ip = mtod(m, struct ip *); 714 dst_ip = ip->ip_src; 715 if ((*args)->eh == NULL || 716 (m->m_pkthdr.len >= sizeof(struct ip) && 717 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 718 hlen = ip->ip_hl << 2; 719 } 720 *cmd_ctl = IP_FW_CTL_NO; 721 if (hlen > 0) { 722 struct ifnet *tif; 723 tif = INADDR_TO_IFP(&dst_ip); 724 *cmd_val = (tif != NULL); 725 } else { 726 *cmd_val = IP_FW_NOT_MATCH; 727 } 728 } 729 730 void 731 check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 732 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 733 { 734 struct in_addr dst_ip; 735 u_int hlen = 0; 736 struct mbuf *m = (*args)->m; 737 struct ip *ip = mtod(m, struct ip *); 738 dst_ip = ip->ip_src; 739 if ((*args)->eh == NULL || 740 (m->m_pkthdr.len >= sizeof(struct ip) && 741 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 742 hlen = ip->ip_hl << 2; 743 } 744 745 *cmd_ctl = IP_FW_CTL_NO; 746 *cmd_val = (hlen > 0 && 747 ((ipfw_insn_ip *)cmd)->addr.s_addr == 748 (dst_ip.s_addr & 749 ((ipfw_insn_ip *)cmd)->mask.s_addr)); 750 } 751 752 void 753 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 754 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 755 { 756 struct ip_fw_state *state; 757 int limited = 0; 758 759 *cmd_ctl = IP_FW_CTL_NO; 760 state = lookup_state(*args, cmd, &limited, 1); 761 if (limited == 1) { 762 *cmd_val = IP_FW_NOT_MATCH; 763 } else { 764 if (state == NULL) 765 state = install_state(*f, cmd, *args); 766 767 if (state != NULL) { 768 state->pcnt++; 769 state->bcnt += ip_len; 770 state->timestamp = time_second; 771 *cmd_val = IP_FW_MATCH; 772 } else { 773 *cmd_val = IP_FW_NOT_MATCH; 774 } 775 } 776 } 777 778 void 779 check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 780 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 781 { 782 struct m_tag *mtag = m_tag_locate((*args)->m, 783 MTAG_IPFW, cmd->arg1, NULL); 784 if (mtag == NULL) { 785 mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT); 786 if (mtag != NULL) 787 m_tag_prepend((*args)->m, mtag); 788 789 } 790 (*f)->pcnt++; 791 (*f)->bcnt += ip_len; 792 (*f)->timestamp = time_second; 793 *cmd_ctl = IP_FW_CTL_NEXT; 794 } 795 796 void 797 check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 798 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 799 { 800 struct m_tag *mtag = m_tag_locate((*args)->m, 801 MTAG_IPFW, cmd->arg1, NULL); 802 if (mtag != NULL) 803 m_tag_delete((*args)->m, mtag); 804 805 (*f)->pcnt++; 806 (*f)->bcnt += ip_len; 807 (*f)->timestamp = time_second; 808 *cmd_ctl = IP_FW_CTL_NEXT; 809 } 810 811 void 812 check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 813 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 814 { 815 *cmd_ctl = IP_FW_CTL_NO; 816 if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL ) 817 *cmd_val = IP_FW_MATCH; 818 else 819 *cmd_val = IP_FW_NOT_MATCH; 820 } 821 822 void 823 check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 824 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 825 { 826 *cmd_ctl = IP_FW_CTL_NO; 827 if ((*args)->f_id.src_port == cmd->arg1) 828 *cmd_val = IP_FW_MATCH; 829 else 830 *cmd_val = IP_FW_NOT_MATCH; 831 } 832 833 void 834 check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 835 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 836 { 837 *cmd_ctl = IP_FW_CTL_NO; 838 if ((*args)->f_id.dst_port == cmd->arg1) 839 *cmd_val = IP_FW_MATCH; 840 else 841 *cmd_val = IP_FW_NOT_MATCH; 842 } 843 844 void 845 check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 846 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 847 { 848 struct in_addr src_ip; 849 u_int hlen = 0; 850 struct mbuf *m = (*args)->m; 851 struct ip *ip = mtod(m, struct ip *); 852 src_ip = ip->ip_src; 853 if ((*args)->eh == NULL || 854 (m->m_pkthdr.len >= sizeof(struct ip) && 855 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 856 hlen = ip->ip_hl << 2; 857 } 858 *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr); 859 *cmd_ctl = IP_FW_CTL_NO; 860 if (*cmd_val && (*args)->f_id.src_port == cmd->arg1) 861 *cmd_val = IP_FW_MATCH; 862 else 863 *cmd_val = IP_FW_NOT_MATCH; 864 } 865 866 void 867 check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 868 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 869 { 870 struct in_addr dst_ip; 871 u_int hlen = 0; 872 struct mbuf *m = (*args)->m; 873 struct ip *ip = mtod(m, struct ip *); 874 dst_ip = ip->ip_dst; 875 if ((*args)->eh == NULL || 876 (m->m_pkthdr.len >= sizeof(struct ip) && 877 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 878 hlen = ip->ip_hl << 2; 879 } 880 *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr); 881 *cmd_ctl = IP_FW_CTL_NO; 882 if (*cmd_val && (*args)->f_id.dst_port == cmd->arg1) 883 *cmd_val = IP_FW_MATCH; 884 else 885 *cmd_val = IP_FW_NOT_MATCH; 886 } 887 888 889 890 static void 891 ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state) 892 { 893 struct ip_fw_state *state; 894 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 895 struct ipfw_state_context *state_ctx; 896 state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))]; 897 state = kmalloc(sizeof(struct ip_fw_state), 898 M_IPFW3_BASIC, M_WAITOK | M_ZERO); 899 struct ip_fw *rule = ctx->ipfw_rule_chain; 900 while (rule != NULL) { 901 if (rule->rulenum == ioc_state->rulenum) { 902 break; 903 } 904 rule = rule->next; 905 } 906 if (rule == NULL) 907 return; 908 909 state->stub = rule; 910 911 state->lifetime = ioc_state->lifetime == 0 ? 912 state_lifetime : ioc_state->lifetime ; 913 state->timestamp = time_second; 914 state->expiry = ioc_state->expiry; 915 bcopy(&ioc_state->flow_id, &state->flow_id, 916 sizeof(struct ipfw_flow_id)); 917 //append the state into the state chian 918 if (state_ctx->last != NULL) 919 state_ctx->last->next = state; 920 else 921 state_ctx->state = state; 922 923 state_ctx->last = state; 924 state_ctx->count++; 925 } 926 927 /* 928 * if rule is NULL 929 * flush all states 930 * else 931 * flush states which stub is the rule 932 */ 933 static void 934 ipfw_basic_flush_state(struct ip_fw *rule) 935 { 936 struct ipfw_state_context *state_ctx; 937 struct ip_fw_state *state,*the_state, *prev_state; 938 struct ipfw_context *ctx; 939 int i; 940 941 ctx = ipfw_ctx[mycpuid]; 942 for (i = 0; i < state_hash_size; i++) { 943 state_ctx = &ctx->state_ctx[i]; 944 if (state_ctx != NULL) { 945 state = state_ctx->state; 946 prev_state = NULL; 947 while (state != NULL) { 948 if (rule != NULL && state->stub != rule) { 949 prev_state = state; 950 state = state->next; 951 } else { 952 if (prev_state == NULL) 953 state_ctx->state = state->next; 954 else 955 prev_state->next = state->next; 956 957 the_state = state; 958 state = state->next; 959 kfree(the_state, M_IPFW3_BASIC); 960 state_ctx->count--; 961 if (state == NULL) 962 state_ctx->last = prev_state; 963 964 } 965 } 966 } 967 } 968 } 969 970 /* 971 * clean up expired state in every tick 972 */ 973 static void 974 ipfw_cleanup_expired_state(netmsg_t nmsg) 975 { 976 struct ip_fw_state *state,*the_state,*prev_state; 977 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 978 struct ipfw_state_context *state_ctx; 979 int i; 980 981 for (i = 0; i < state_hash_size; i++) { 982 prev_state = NULL; 983 state_ctx = &(ctx->state_ctx[i]); 984 if (ctx->state_ctx != NULL) { 985 state = state_ctx->state; 986 while (state != NULL) { 987 if (IS_EXPIRED(state)) { 988 if (prev_state == NULL) 989 state_ctx->state = state->next; 990 else 991 prev_state->next = state->next; 992 993 the_state =state; 994 state = state->next; 995 996 if (the_state == state_ctx->last) 997 state_ctx->last = NULL; 998 999 1000 kfree(the_state, M_IPFW3_BASIC); 1001 state_ctx->count--; 1002 } else { 1003 prev_state = state; 1004 state = state->next; 1005 } 1006 } 1007 } 1008 } 1009 ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1); 1010 } 1011 1012 static void 1013 ipfw_tick(void *dummy __unused) 1014 { 1015 struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg; 1016 KKASSERT(mycpuid == IPFW_CFGCPUID); 1017 1018 crit_enter(); 1019 KKASSERT(lmsg->ms_flags & MSGF_DONE); 1020 if (IPFW_BASIC_LOADED) { 1021 lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg); 1022 /* ipfw_timeout_netmsg's handler reset this callout */ 1023 } 1024 crit_exit(); 1025 1026 struct netmsg_base *msg; 1027 struct netmsg_base the_msg; 1028 msg = &the_msg; 1029 bzero(msg,sizeof(struct netmsg_base)); 1030 1031 netmsg_init(msg, NULL, &curthread->td_msgport, 0, 1032 ipfw_cleanup_expired_state); 1033 ifnet_domsg(&msg->lmsg, 0); 1034 } 1035 1036 static void 1037 ipfw_tick_dispatch(netmsg_t nmsg) 1038 { 1039 IPFW_ASSERT_CFGPORT(&curthread->td_msgport); 1040 KKASSERT(IPFW_BASIC_LOADED); 1041 1042 /* Reply ASAP */ 1043 crit_enter(); 1044 lwkt_replymsg(&nmsg->lmsg, 0); 1045 crit_exit(); 1046 1047 callout_reset(&ipfw_tick_callout, 1048 state_expiry_check_interval * hz, ipfw_tick, NULL); 1049 } 1050 1051 static void 1052 ipfw_basic_init_dispatch(netmsg_t nmsg) 1053 { 1054 IPFW_ASSERT_CFGPORT(&curthread->td_msgport); 1055 KKASSERT(IPFW3_LOADED); 1056 1057 int error = 0; 1058 callout_init_mp(&ipfw_tick_callout); 1059 netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport, 1060 MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch); 1061 callout_reset(&ipfw_tick_callout, 1062 state_expiry_check_interval * hz, ipfw_tick, NULL); 1063 lwkt_replymsg(&nmsg->lmsg, error); 1064 ip_fw_basic_loaded=1; 1065 } 1066 1067 static int 1068 ipfw_basic_init(void) 1069 { 1070 ipfw_basic_flush_state_prt = ipfw_basic_flush_state; 1071 ipfw_basic_append_state_prt = ipfw_basic_add_state; 1072 1073 register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME); 1074 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT, 1075 (filter_func)check_count); 1076 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO, 1077 (filter_func)check_skipto); 1078 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD, 1079 (filter_func)check_forward); 1080 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE, 1081 (filter_func)check_keep_state); 1082 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE, 1083 (filter_func)check_check_state); 1084 1085 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1086 O_BASIC_IN, (filter_func)check_in); 1087 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1088 O_BASIC_OUT, (filter_func)check_out); 1089 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1090 O_BASIC_VIA, (filter_func)check_via); 1091 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1092 O_BASIC_XMIT, (filter_func)check_via); 1093 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1094 O_BASIC_RECV, (filter_func)check_via); 1095 1096 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1097 O_BASIC_PROTO, (filter_func)check_proto); 1098 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1099 O_BASIC_PROB, (filter_func)check_prob); 1100 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1101 O_BASIC_IP_SRC, (filter_func)check_from); 1102 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1103 O_BASIC_IP_SRC_LOOKUP, (filter_func)check_from_lookup); 1104 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1105 O_BASIC_IP_SRC_ME, (filter_func)check_from_me); 1106 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1107 O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask); 1108 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1109 O_BASIC_IP_DST, (filter_func)check_to); 1110 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1111 O_BASIC_IP_DST_LOOKUP, (filter_func)check_to_lookup); 1112 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1113 O_BASIC_IP_DST_ME, (filter_func)check_to_me); 1114 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1115 O_BASIC_IP_DST_MASK, (filter_func)check_to_mask); 1116 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1117 O_BASIC_TAG, (filter_func)check_tag); 1118 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1119 O_BASIC_UNTAG, (filter_func)check_untag); 1120 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1121 O_BASIC_TAGGED, (filter_func)check_tagged); 1122 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1123 O_BASIC_IP_SRCPORT, (filter_func)check_src_port); 1124 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1125 O_BASIC_IP_DSTPORT, (filter_func)check_dst_port); 1126 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1127 O_BASIC_IP_SRC_N_PORT, (filter_func)check_src_n_port); 1128 register_ipfw_filter_funcs(MODULE_BASIC_ID, 1129 O_BASIC_IP_DST_N_PORT, (filter_func)check_dst_n_port); 1130 1131 int cpu; 1132 struct ipfw_context *ctx; 1133 1134 for (cpu = 0; cpu < ncpus; cpu++) { 1135 ctx = ipfw_ctx[cpu]; 1136 if (ctx != NULL) { 1137 ctx->state_ctx = kmalloc(state_hash_size * 1138 sizeof(struct ipfw_state_context), 1139 M_IPFW3_BASIC, M_WAITOK | M_ZERO); 1140 ctx->state_hash_size = state_hash_size; 1141 } 1142 } 1143 1144 struct netmsg_base smsg; 1145 netmsg_init(&smsg, NULL, &curthread->td_msgport, 1146 0, ipfw_basic_init_dispatch); 1147 lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0); 1148 return 0; 1149 } 1150 1151 static void 1152 ipfw_basic_stop_dispatch(netmsg_t nmsg) 1153 { 1154 IPFW_ASSERT_CFGPORT(&curthread->td_msgport); 1155 KKASSERT(IPFW3_LOADED); 1156 int error = 0; 1157 callout_stop(&ipfw_tick_callout); 1158 netmsg_service_sync(); 1159 crit_enter(); 1160 lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg); 1161 crit_exit(); 1162 lwkt_replymsg(&nmsg->lmsg, error); 1163 ip_fw_basic_loaded=0; 1164 } 1165 1166 static int 1167 ipfw_basic_stop(void) 1168 { 1169 int cpu,i; 1170 struct ipfw_state_context *state_ctx; 1171 struct ip_fw_state *state,*the_state; 1172 struct ipfw_context *ctx; 1173 if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) { 1174 ipfw_basic_flush_state_prt = NULL; 1175 ipfw_basic_append_state_prt = NULL; 1176 1177 for (cpu = 0; cpu < ncpus; cpu++) { 1178 ctx = ipfw_ctx[cpu]; 1179 if (ctx != NULL) { 1180 for (i = 0; i < state_hash_size; i++) { 1181 state_ctx = &ctx->state_ctx[i]; 1182 if (state_ctx != NULL) { 1183 state = state_ctx->state; 1184 while (state != NULL) { 1185 the_state = state; 1186 state = state->next; 1187 if (the_state == 1188 state_ctx->last) 1189 state_ctx->last = NULL; 1190 1191 kfree(the_state, 1192 M_IPFW3_BASIC); 1193 } 1194 } 1195 } 1196 ctx->state_hash_size = 0; 1197 kfree(ctx->state_ctx, M_IPFW3_BASIC); 1198 ctx->state_ctx = NULL; 1199 } 1200 } 1201 struct netmsg_base smsg; 1202 netmsg_init(&smsg, NULL, &curthread->td_msgport, 1203 0, ipfw_basic_stop_dispatch); 1204 return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0); 1205 } 1206 return 1; 1207 } 1208 1209 1210 static int 1211 ipfw3_basic_modevent(module_t mod, int type, void *data) 1212 { 1213 int err; 1214 switch (type) { 1215 case MOD_LOAD: 1216 err = ipfw_basic_init(); 1217 break; 1218 case MOD_UNLOAD: 1219 err = ipfw_basic_stop(); 1220 break; 1221 default: 1222 err = 1; 1223 } 1224 return err; 1225 } 1226 1227 static moduledata_t ipfw3_basic_mod = { 1228 "ipfw3_basic", 1229 ipfw3_basic_modevent, 1230 NULL 1231 }; 1232 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY); 1233 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1); 1234 MODULE_VERSION(ipfw3_basic, 1); 1235