1 /* 2 * Copyright (c) 2015 -2018 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Bill Yuan <bycn82@dragonflybsd.org> 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 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/kernel.h> 42 #include <sys/proc.h> 43 #include <sys/socket.h> 44 #include <sys/socketvar.h> 45 #include <sys/sysctl.h> 46 #include <sys/syslog.h> 47 #include <sys/ucred.h> 48 #include <sys/in_cksum.h> 49 #include <sys/lock.h> 50 #include <sys/thread2.h> 51 #include <sys/mplock2.h> 52 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.h> 58 #include <netinet/ip_var.h> 59 #include <netinet/ip_icmp.h> 60 #include <netinet/tcp.h> 61 #include <netinet/tcp_timer.h> 62 #include <netinet/tcp_var.h> 63 #include <netinet/tcpip.h> 64 #include <netinet/udp.h> 65 #include <netinet/udp_var.h> 66 #include <netinet/ip_divert.h> 67 #include <netinet/if_ether.h> 68 69 #include <net/if.h> 70 #include <net/route.h> 71 #include <net/pfil.h> 72 #include <net/netmsg2.h> 73 #include <net/ethernet.h> 74 75 #include <net/ipfw3/ip_fw.h> 76 #include <net/ipfw3_basic/ip_fw3_table.h> 77 78 MALLOC_DEFINE(M_IPFW3_TABLE, "IPFW3_TABLE", "mem for ip_fw3 table"); 79 80 extern struct ipfw3_context *fw3_ctx[MAXCPU]; 81 82 /* 83 * activate/create the table by setup the type and reset counts. 84 */ 85 static void 86 table_create_dispatch(netmsg_t nmsg) 87 { 88 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 89 struct ipfw_ioc_table *ioc_table; 90 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 91 struct ipfw3_table_context *table_ctx; 92 ioc_table = tbmsg->ioc_table; 93 int id = ioc_table->id; 94 95 table_ctx = ctx->table_ctx; 96 table_ctx += id; 97 table_ctx->type = ioc_table->type; 98 table_ctx->count = 0; 99 strlcpy(table_ctx->name , ioc_table->name, IPFW_TABLE_NAME_LEN); 100 if (table_ctx->type == 1) { 101 rn_inithead((void **)&table_ctx->mask, NULL, 0); 102 rn_inithead((void **)&table_ctx->node, table_ctx->mask, 32); 103 } else if (table_ctx->type == 2) { 104 rn_inithead((void **)&table_ctx->mask, NULL, 0); 105 rn_inithead((void **)&table_ctx->node, table_ctx->mask, 48); 106 } else { 107 goto done; 108 } 109 done: 110 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 111 } 112 113 /* 114 * clean the table, especially the node 115 */ 116 static void 117 table_delete_dispatch(netmsg_t nmsg) 118 { 119 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 120 struct ipfw_ioc_table *ioc_tbl; 121 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 122 struct ipfw3_table_context *table_ctx; 123 struct radix_node_head *rnh; 124 125 ioc_tbl = tbmsg->ioc_table; 126 table_ctx = ctx->table_ctx; 127 table_ctx += ioc_tbl->id; 128 table_ctx->count = 0; 129 130 if (table_ctx->type == 1) { 131 rnh = table_ctx->node; 132 rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh); 133 } else if (table_ctx->type == 2) { 134 rnh = table_ctx->node; 135 rnh->rnh_walktree(rnh, flush_table_mac_entry, rnh); 136 } 137 table_ctx->type = 0; 138 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 139 } 140 141 static void 142 table_append_dispatch(netmsg_t nmsg) 143 { 144 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 145 struct ipfw_ioc_table *ioc_tbl; 146 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 147 struct ipfw3_table_context *table_ctx; 148 struct radix_node_head *rnh; 149 150 uint8_t mlen; 151 152 ioc_tbl = tbmsg->ioc_table; 153 table_ctx = ctx->table_ctx; 154 table_ctx += ioc_tbl->id; 155 if (table_ctx->type != ioc_tbl->type) 156 goto done; 157 158 if (table_ctx->type == 1 ) { 159 struct table_ip_entry *ent; 160 161 rnh = table_ctx->node; 162 ent = kmalloc(sizeof(struct table_ip_entry), 163 M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 164 165 if (ent == NULL) 166 return; 167 mlen = ioc_tbl->ip_ent->masklen; 168 ent->addr.sin_len = ent->mask.sin_len = 8; 169 ent->mask.sin_addr.s_addr = htonl(~((1 << (32 - mlen)) - 1)); 170 ent->addr.sin_addr.s_addr = ioc_tbl->ip_ent->addr & 171 ent->mask.sin_addr.s_addr; 172 173 if (rnh->rnh_addaddr((char *)&ent->addr, 174 (char *)&ent->mask, rnh, 175 (void *)ent->rn) != NULL) { 176 table_ctx->count++; 177 } 178 } else if (table_ctx->type == 2 ) { 179 struct table_mac_entry *ent; 180 181 rnh = table_ctx->node; 182 ent = kmalloc(sizeof(struct table_mac_entry), 183 M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 184 if (ent == NULL) 185 return; 186 ent->addr.sa_len = 8; 187 strncpy(ent->addr.sa_data, ioc_tbl->mac_ent->addr.octet, 6); 188 189 if (rnh->rnh_addaddr((char *)&ent->addr, 190 NULL, rnh, (void *)ent->rn) != NULL) { 191 table_ctx->count++; 192 } 193 } 194 195 done: 196 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 197 } 198 199 static void 200 table_remove_dispatch(netmsg_t nmsg) 201 { 202 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 203 struct ipfw_ioc_table *ioc_tbl; 204 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 205 struct ipfw3_table_context *table_ctx; 206 struct radix_node_head *rnh; 207 struct table_entry *ent; 208 struct sockaddr_in sa, mask; 209 in_addr_t addr; 210 uint8_t mlen; 211 212 ioc_tbl = tbmsg->ioc_table; 213 table_ctx = ctx->table_ctx; 214 table_ctx += ioc_tbl->id; 215 if (table_ctx->type != ioc_tbl->type) 216 goto done; 217 218 rnh = table_ctx->node; 219 220 mlen = ioc_tbl->ip_ent->masklen; 221 addr = ioc_tbl->ip_ent->addr; 222 223 sa.sin_len = mask.sin_len = 8; 224 mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 225 sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 226 227 ent = (struct table_entry *)rnh->rnh_deladdr((char *)&sa, (char *)&mask, rnh); 228 if (ent != NULL) { 229 table_ctx->count--; 230 kfree(ent, M_IPFW3_TABLE); 231 } 232 done: 233 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 234 } 235 236 int 237 flush_table_ip_entry(struct radix_node *rn, void *arg) 238 { 239 struct radix_node_head *rnh = arg; 240 struct table_ip_entry *ent; 241 242 ent = (struct table_ip_entry *) 243 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 244 if (ent != NULL) 245 kfree(ent, M_IPFW3_TABLE); 246 return (0); 247 } 248 249 int 250 flush_table_mac_entry(struct radix_node *rn, void *arg) 251 { 252 struct radix_node_head *rnh = arg; 253 struct table_mac_entry *ent; 254 255 ent = (struct table_mac_entry *) 256 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 257 if (ent != NULL) 258 kfree(ent, M_IPFW3_TABLE); 259 return (0); 260 } 261 262 static void 263 table_flush_dispatch(netmsg_t nmsg) 264 { 265 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 266 struct ipfw_ioc_table *ioc_tbl; 267 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 268 struct ipfw3_table_context *table_ctx; 269 struct radix_node_head *rnh; 270 271 ioc_tbl = tbmsg->ioc_table; 272 table_ctx = ctx->table_ctx; 273 table_ctx += ioc_tbl->id; 274 rnh = table_ctx->node; 275 table_ctx->count = 0; 276 277 rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh); 278 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 279 } 280 281 /* 282 * rename the table 283 */ 284 static void 285 table_rename_dispatch(netmsg_t nmsg) 286 { 287 struct netmsg_table *tbmsg = (struct netmsg_table *)nmsg; 288 struct ipfw_ioc_table *ioc_tbl; 289 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 290 struct ipfw3_table_context *table_ctx; 291 292 ioc_tbl = tbmsg->ioc_table; 293 table_ctx = ctx->table_ctx; 294 table_ctx += ioc_tbl->id; 295 strlcpy(table_ctx->name, ioc_tbl->name, IPFW_TABLE_NAME_LEN); 296 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 297 } 298 299 /* 300 * list all the overview information about each table 301 */ 302 int 303 ip_fw3_ctl_table_list(struct sockopt *sopt) 304 { 305 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 306 struct ipfw3_table_context *table_ctx = ctx->table_ctx; 307 struct ipfw_ioc_table *ioc_table; 308 int i, error = 0, size; 309 310 size = IPFW_TABLES_MAX * sizeof(struct ipfw_ioc_table); 311 if (sopt->sopt_valsize < size) { 312 /* sopt_val is not big enough */ 313 bzero(sopt->sopt_val, sopt->sopt_valsize); 314 return 0; 315 } 316 ioc_table = (struct ipfw_ioc_table *)sopt->sopt_val; 317 for (i = 0; i < IPFW_TABLES_MAX; i++, ioc_table++, table_ctx++) { 318 ioc_table->id = i; 319 ioc_table->type = table_ctx->type; 320 ioc_table->count = table_ctx->count; 321 strlcpy(ioc_table->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 322 } 323 sopt->sopt_valsize = size; 324 return error; 325 } 326 327 /* 328 * remove an item from the table 329 */ 330 int 331 ip_fw3_ctl_table_remove(struct sockopt *sopt) 332 { 333 struct netmsg_table tbmsg; 334 bzero(&tbmsg,sizeof(tbmsg)); 335 tbmsg.ioc_table = sopt->sopt_val; 336 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 337 0, table_remove_dispatch); 338 netisr_domsg(&tbmsg.base, 0); 339 return tbmsg.retval; 340 } 341 342 /* 343 * flush everything inside the table 344 */ 345 int 346 ip_fw3_ctl_table_flush(struct sockopt *sopt) 347 { 348 struct netmsg_table tbmsg; 349 bzero(&tbmsg,sizeof(tbmsg)); 350 tbmsg.ioc_table = sopt->sopt_val; 351 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 352 0, table_flush_dispatch); 353 netisr_domsg(&tbmsg.base, 0); 354 return tbmsg.retval; 355 } 356 357 /* 358 * dump the entries into the ioc_table 359 */ 360 int 361 dump_table_ip_entry(struct radix_node *rn, void *arg) 362 { 363 struct table_ip_entry *ent = (struct table_ip_entry *)rn; 364 struct ipfw_ioc_table_ip_entry *ioc_ent; 365 struct ipfw_ioc_table *tbl = arg; 366 struct sockaddr_in *addr, *mask; 367 368 addr = &ent->addr; 369 mask = &ent->mask; 370 371 ioc_ent = &tbl->ip_ent[tbl->count]; 372 if (in_nullhost(mask->sin_addr)) 373 ioc_ent->masklen = 0; 374 else 375 ioc_ent->masklen = 33 - ffs(ntohl(mask->sin_addr.s_addr)); 376 ioc_ent->addr = addr->sin_addr.s_addr; 377 tbl->count++; 378 return (0); 379 } 380 381 int 382 dump_table_mac_entry(struct radix_node *rn, void *arg) 383 { 384 struct table_mac_entry *ent = (struct table_mac_entry *)rn; 385 struct ipfw_ioc_table_mac_entry *ioc_ent; 386 struct ipfw_ioc_table *tbl = arg; 387 ioc_ent = &tbl->mac_ent[tbl->count]; 388 strncpy(ioc_ent->addr.octet, ent->addr.sa_data, 6); 389 tbl->count++; 390 return (0); 391 } 392 393 /* 394 * get and display all items in the table 395 */ 396 int 397 ip_fw3_ctl_table_show(struct sockopt *sopt) 398 { 399 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 400 struct ipfw3_table_context *table_ctx; 401 struct radix_node_head *rnh; 402 struct ipfw_ioc_table *tbl; 403 void *data; 404 int size; 405 406 int *id = (int *)sopt->sopt_val; 407 table_ctx = ctx->table_ctx; 408 table_ctx += *id; 409 if (table_ctx->type == 1) { 410 size = table_ctx->count * sizeof(struct ipfw_ioc_table_ip_entry) + 411 sizeof(struct ipfw_ioc_table); 412 if (sopt->sopt_valsize < size) { 413 /* sopt_val is not big enough */ 414 bzero(sopt->sopt_val, sopt->sopt_valsize); 415 return 0; 416 } 417 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 418 tbl = (struct ipfw_ioc_table *)data; 419 tbl->id = *id; 420 tbl->type = table_ctx->type; 421 strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 422 rnh = table_ctx->node; 423 rnh->rnh_walktree(rnh, dump_table_ip_entry, tbl); 424 bcopy(tbl, sopt->sopt_val, size); 425 sopt->sopt_valsize = size; 426 kfree(data, M_IPFW3_TABLE); 427 } else if (table_ctx->type == 2) { 428 size = table_ctx->count * sizeof(struct ipfw_ioc_table_mac_entry) + 429 sizeof(struct ipfw_ioc_table); 430 if (sopt->sopt_valsize < size) { 431 /* sopt_val is not big enough */ 432 bzero(sopt->sopt_val, sopt->sopt_valsize); 433 return 0; 434 } 435 data = kmalloc(size, M_IPFW3_TABLE, M_NOWAIT | M_ZERO); 436 tbl = (struct ipfw_ioc_table *)data; 437 tbl->id = *id; 438 tbl->type = table_ctx->type; 439 strlcpy(tbl->name, table_ctx->name, IPFW_TABLE_NAME_LEN); 440 rnh = table_ctx->node; 441 rnh->rnh_walktree(rnh, dump_table_mac_entry, tbl); 442 bcopy(tbl, sopt->sopt_val, size); 443 sopt->sopt_valsize = size; 444 kfree(data, M_IPFW3_TABLE); 445 } 446 return 0; 447 } 448 449 /* 450 * test whether the ip is in the table 451 */ 452 int 453 ip_fw3_ctl_table_test(struct sockopt *sopt) 454 { 455 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 456 struct ipfw3_table_context *table_ctx; 457 struct radix_node_head *rnh; 458 struct ipfw_ioc_table *tbl; 459 460 tbl = (struct ipfw_ioc_table *)sopt->sopt_val; 461 table_ctx = ctx->table_ctx; 462 table_ctx += tbl->id; 463 464 if (table_ctx->type != tbl->type) 465 goto done; 466 467 rnh = table_ctx->node; 468 if (tbl->type == 1) { 469 struct sockaddr_in sa; 470 sa.sin_len = 8; 471 sa.sin_addr.s_addr = tbl->ip_ent->addr; 472 473 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL) 474 return 0; 475 } else if (tbl->type == 2) { 476 struct sockaddr sa; 477 sa.sa_len = 8; 478 strncpy(sa.sa_data, tbl->mac_ent->addr.octet, 6); 479 480 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL) 481 return 0; 482 } else { 483 /* XXX TODO */ 484 } 485 done: 486 return 1; 487 } 488 489 /* 490 * activate the table 491 */ 492 int 493 ip_fw3_ctl_table_create(struct sockopt *sopt) 494 { 495 struct netmsg_table tbmsg; 496 bzero(&tbmsg,sizeof(tbmsg)); 497 tbmsg.ioc_table = sopt->sopt_val; 498 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 499 0, table_create_dispatch); 500 netisr_domsg(&tbmsg.base, 0); 501 return tbmsg.retval; 502 } 503 504 /* 505 * deactivate the table 506 */ 507 int 508 ip_fw3_ctl_table_delete(struct sockopt *sopt) 509 { 510 struct netmsg_table tbmsg; 511 bzero(&tbmsg,sizeof(tbmsg)); 512 tbmsg.ioc_table = sopt->sopt_val; 513 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 514 0, table_delete_dispatch); 515 netisr_domsg(&tbmsg.base, 0); 516 return tbmsg.retval; 517 } 518 519 /* 520 * append an item into the table 521 */ 522 int 523 ip_fw3_ctl_table_append(struct sockopt *sopt) 524 { 525 struct netmsg_table tbmsg; 526 bzero(&tbmsg,sizeof(tbmsg)); 527 tbmsg.ioc_table = sopt->sopt_val; 528 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 529 0, table_append_dispatch); 530 netisr_domsg(&tbmsg.base, 0); 531 return tbmsg.retval; 532 } 533 534 /* 535 * rename an table 536 */ 537 int 538 ip_fw3_ctl_table_rename(struct sockopt *sopt) 539 { 540 struct netmsg_table tbmsg; 541 bzero(&tbmsg,sizeof(tbmsg)); 542 tbmsg.ioc_table = sopt->sopt_val; 543 netmsg_init(&tbmsg.base, NULL, &curthread->td_msgport, 544 0, table_rename_dispatch); 545 netisr_domsg(&tbmsg.base, 0); 546 return tbmsg.retval; 547 } 548 549 /* 550 * sockopt handler 551 */ 552 int 553 ip_fw3_ctl_table_sockopt(struct sockopt *sopt) 554 { 555 int error = 0; 556 switch (sopt->sopt_name) { 557 case IP_FW_TABLE_CREATE: 558 error = ip_fw3_ctl_table_create(sopt); 559 break; 560 case IP_FW_TABLE_DELETE: 561 error = ip_fw3_ctl_table_delete(sopt); 562 break; 563 case IP_FW_TABLE_APPEND: 564 error = ip_fw3_ctl_table_append(sopt); 565 break; 566 case IP_FW_TABLE_REMOVE: 567 error = ip_fw3_ctl_table_remove(sopt); 568 break; 569 case IP_FW_TABLE_LIST: 570 error = ip_fw3_ctl_table_list(sopt); 571 break; 572 case IP_FW_TABLE_FLUSH: 573 error = ip_fw3_ctl_table_flush(sopt); 574 break; 575 case IP_FW_TABLE_SHOW: 576 error = ip_fw3_ctl_table_show(sopt); 577 break; 578 case IP_FW_TABLE_TEST: 579 error = ip_fw3_ctl_table_test(sopt); 580 break; 581 case IP_FW_TABLE_RENAME: 582 error = ip_fw3_ctl_table_rename(sopt); 583 break; 584 default: 585 kprintf("ipfw table invalid socket option %d\n", 586 sopt->sopt_name); 587 } 588 return error; 589 } 590 591 static void 592 table_init_ctx_dispatch(netmsg_t nmsg) 593 { 594 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 595 ctx->table_ctx = kmalloc(sizeof(struct ipfw3_table_context) * IPFW_TABLES_MAX, 596 M_IPFW3_TABLE, M_WAITOK | M_ZERO); 597 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 598 } 599 600 /* 601 * release the memory of the tables 602 */ 603 void 604 table_fini(void) 605 { 606 struct ipfw3_table_context *table_ctx, *tmp_table; 607 struct radix_node_head *rnh; 608 int cpu, id; 609 for (cpu = 0; cpu < ncpus; cpu++) { 610 table_ctx = fw3_ctx[cpu]->table_ctx; 611 tmp_table = table_ctx; 612 for (id = 0; id < IPFW_TABLES_MAX; id++, table_ctx++) { 613 if (table_ctx->type == 1) { 614 rnh = table_ctx->node; 615 rnh->rnh_walktree(rnh, flush_table_ip_entry, rnh); 616 } else if (table_ctx->type == 2) { 617 rnh = table_ctx->node; 618 rnh->rnh_walktree(rnh, flush_table_mac_entry, rnh); 619 } 620 } 621 kfree(tmp_table, M_IPFW3_TABLE); 622 } 623 } 624 625 /* 626 * it will be invoked during init of ipfw3 627 * this function will prepare the tables 628 */ 629 void 630 table_init_dispatch(netmsg_t nmsg) 631 { 632 int error = 0; 633 struct netmsg_base nmsg_base; 634 bzero(&nmsg_base, sizeof(nmsg_base)); 635 netmsg_init(&nmsg_base, NULL, &curthread->td_msgport, 636 0, table_init_ctx_dispatch); 637 netisr_domsg(&nmsg_base, 0); 638 lwkt_replymsg(&nmsg->lmsg, error); 639 } 640