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