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