1 /* $FreeBSD: src/sys/contrib/pf/net/if_pfsync.c,v 1.11 2004/08/14 15:32:40 dwmalone Exp $ */ 2 /* $OpenBSD: if_pfsync.c,v 1.26 2004/03/28 18:14:20 mcbride Exp $ */ 3 /* $DragonFly: src/sys/net/pf/if_pfsync.c,v 1.5 2006/09/05 00:55:47 dillon Exp $ */ 4 5 /* 6 * Copyright (c) 2004 The DragonFly Project. All rights reserved. 7 * 8 * Copyright (c) 2002 Michael Shalayeff 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "opt_inet.h" 34 #include "opt_inet6.h" 35 36 #include <sys/param.h> 37 #include <sys/proc.h> 38 #include <sys/systm.h> 39 #include <sys/time.h> 40 #include <sys/mbuf.h> 41 #include <sys/socket.h> 42 #include <sys/kernel.h> 43 #include <sys/malloc.h> 44 #include <sys/module.h> 45 #include <sys/sockio.h> 46 #include <sys/thread2.h> 47 #include <vm/vm_zone.h> 48 49 #include <machine/inttypes.h> 50 51 #include <net/if.h> 52 #include <net/if_types.h> 53 #include <net/route.h> 54 #include <net/bpf.h> 55 56 #ifdef INET 57 #include <netinet/in.h> 58 #include <netinet/in_systm.h> 59 #include <netinet/in_var.h> 60 #include <netinet/ip.h> 61 #include <netinet/ip_var.h> 62 #endif 63 64 #ifdef INET6 65 #ifndef INET 66 #include <netinet/in.h> 67 #endif 68 #include <netinet6/nd6.h> 69 #endif /* INET6 */ 70 71 #include <net/pf/pfvar.h> 72 #include <net/pf/if_pfsync.h> 73 74 #define PFSYNCNAME "pfsync" 75 76 #define PFSYNC_MINMTU \ 77 (sizeof(struct pfsync_header) + sizeof(struct pf_state)) 78 79 #ifdef PFSYNCDEBUG 80 #define DPRINTF(x) do { if (pfsyncdebug) printf x ; } while (0) 81 int pfsyncdebug; 82 #else 83 #define DPRINTF(x) 84 #endif 85 86 int pfsync_sync_ok; 87 struct pfsyncstats pfsyncstats; 88 89 static void pfsync_clone_destroy(struct ifnet *); 90 static int pfsync_clone_create(struct if_clone *, int); 91 void pfsync_setmtu(struct pfsync_softc *, int); 92 int pfsync_insert_net_state(struct pfsync_state *); 93 int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 94 struct rtentry *); 95 int pfsyncioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 96 void pfsyncstart(struct ifnet *); 97 98 struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **); 99 int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *); 100 int pfsync_sendout(struct pfsync_softc *); 101 void pfsync_timeout(void *); 102 void pfsync_send_bus(struct pfsync_softc *, u_int8_t); 103 void pfsync_bulk_update(void *); 104 void pfsync_bulkfail(void *); 105 106 static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface"); 107 static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list; 108 struct if_clone pfsync_cloner = IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, 109 pfsync_clone_destroy, 1, 1); 110 111 static void 112 pfsync_clone_destroy(struct ifnet *ifp) 113 { 114 struct pfsync_softc *sc; 115 116 sc = ifp->if_softc; 117 callout_stop(&sc->sc_tmo); 118 callout_stop(&sc->sc_bulk_tmo); 119 callout_stop(&sc->sc_bulkfail_tmo); 120 121 bpfdetach(ifp); 122 if_detach(ifp); 123 LIST_REMOVE(sc, sc_next); 124 kfree(sc, M_PFSYNC); 125 } 126 127 static int 128 pfsync_clone_create(struct if_clone *ifc, int unit) 129 { 130 struct pfsync_softc *sc; 131 struct ifnet *ifp; 132 133 MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC, 134 M_WAITOK|M_ZERO); 135 136 pfsync_sync_ok = 1; 137 sc->sc_mbuf = NULL; 138 sc->sc_mbuf_net = NULL; 139 sc->sc_statep.s = NULL; 140 sc->sc_statep_net.s = NULL; 141 sc->sc_maxupdates = 128; 142 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); 143 sc->sc_ureq_received = 0; 144 sc->sc_ureq_sent = 0; 145 146 ifp = &sc->sc_if; 147 if_initname(ifp, ifc->ifc_name, unit); 148 ifp->if_ioctl = pfsyncioctl; 149 ifp->if_output = pfsyncoutput; 150 ifp->if_start = pfsyncstart; 151 ifp->if_type = IFT_PFSYNC; 152 ifp->if_snd.ifq_maxlen = ifqmaxlen; 153 ifp->if_hdrlen = PFSYNC_HDRLEN; 154 ifp->if_baudrate = IF_Mbps(100); 155 ifp->if_softc = sc; 156 pfsync_setmtu(sc, MCLBYTES); 157 callout_init(&sc->sc_tmo); 158 callout_init(&sc->sc_bulk_tmo); 159 callout_init(&sc->sc_bulkfail_tmo); 160 if_attach(&sc->sc_if, NULL); 161 162 LIST_INSERT_HEAD(&pfsync_list, sc, sc_next); 163 bpfattach(&sc->sc_if, DLT_PFSYNC, PFSYNC_HDRLEN); 164 165 return (0); 166 } 167 168 /* 169 * Start output on the pfsync interface. 170 */ 171 void 172 pfsyncstart(struct ifnet *ifp) 173 { 174 crit_enter(); 175 IF_DROP(&ifp->if_snd); 176 IF_DRAIN(&ifp->if_snd); 177 crit_exit(); 178 } 179 180 int 181 pfsync_insert_net_state(struct pfsync_state *sp) 182 { 183 struct pf_state *st = NULL; 184 struct pf_rule *r = NULL; 185 struct pfi_kif *kif; 186 187 if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 188 printf("pfsync_insert_net_state: invalid creator id:" 189 " %08" PRIx32 "\n", ntohl(sp->creatorid)); 190 return (EINVAL); 191 } 192 193 kif = pfi_lookup_create(sp->ifname); 194 if (kif == NULL) { 195 if (pf_status.debug >= PF_DEBUG_MISC) 196 printf("pfsync_insert_net_state: " 197 "unknown interface: %s\n", sp->ifname); 198 /* skip this state */ 199 return (0); 200 } 201 202 /* 203 * Just use the default rule until we have infrastructure to find the 204 * best matching rule. 205 */ 206 r = &pf_default_rule; 207 208 if (!r->max_states || r->states < r->max_states) 209 st = pool_get(&pf_state_pl, PR_NOWAIT); 210 if (st == NULL) { 211 pfi_maybe_destroy(kif); 212 return (ENOMEM); 213 } 214 bzero(st, sizeof(*st)); 215 216 st->rule.ptr = r; 217 /* XXX get pointers to nat_rule and anchor */ 218 219 /* fill in the rest of the state entry */ 220 pf_state_host_ntoh(&sp->lan, &st->lan); 221 pf_state_host_ntoh(&sp->gwy, &st->gwy); 222 pf_state_host_ntoh(&sp->ext, &st->ext); 223 224 pf_state_peer_ntoh(&sp->src, &st->src); 225 pf_state_peer_ntoh(&sp->dst, &st->dst); 226 227 bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 228 st->creation = ntohl(sp->creation) + time_second; 229 st->expire = ntohl(sp->expire) + time_second; 230 231 st->af = sp->af; 232 st->proto = sp->proto; 233 st->direction = sp->direction; 234 st->log = sp->log; 235 st->timeout = sp->timeout; 236 st->allow_opts = sp->allow_opts; 237 238 bcopy(sp->id, &st->id, sizeof(st->id)); 239 st->creatorid = sp->creatorid; 240 st->sync_flags = sp->sync_flags | PFSTATE_FROMSYNC; 241 242 243 if (pf_insert_state(kif, st)) { 244 pfi_maybe_destroy(kif); 245 pool_put(&pf_state_pl, st); 246 return (EINVAL); 247 } 248 249 return (0); 250 } 251 252 void 253 pfsync_input(struct mbuf *m, ...) 254 { 255 struct ip *ip = mtod(m, struct ip *); 256 struct pfsync_header *ph; 257 struct pfsync_softc *sc = LIST_FIRST(&pfsync_list); 258 struct pf_state *st, key; 259 struct pfsync_state *sp; 260 struct pfsync_state_upd *up; 261 struct pfsync_state_del *dp; 262 struct pfsync_state_clr *cp; 263 struct pfsync_state_upd_req *rup; 264 struct pfsync_state_bus *bus; 265 struct in_addr src; 266 struct mbuf *mp; 267 int iplen, action, error, i, count, offp; 268 269 pfsyncstats.pfsyncs_ipackets++; 270 271 /* verify that we have a sync interface configured */ 272 if (!sc->sc_sync_ifp || !pf_status.running) 273 goto done; 274 275 /* verify that the packet came in on the right interface */ 276 if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) { 277 pfsyncstats.pfsyncs_badif++; 278 goto done; 279 } 280 281 /* verify that the IP TTL is 255. */ 282 if (ip->ip_ttl != PFSYNC_DFLTTL) { 283 pfsyncstats.pfsyncs_badttl++; 284 goto done; 285 } 286 287 iplen = ip->ip_hl << 2; 288 289 if (m->m_pkthdr.len < iplen + sizeof(*ph)) { 290 pfsyncstats.pfsyncs_hdrops++; 291 goto done; 292 } 293 294 if (iplen + sizeof(*ph) > m->m_len) { 295 if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) { 296 pfsyncstats.pfsyncs_hdrops++; 297 goto done; 298 } 299 ip = mtod(m, struct ip *); 300 } 301 ph = (struct pfsync_header *)((char *)ip + iplen); 302 303 /* verify the version */ 304 if (ph->version != PFSYNC_VERSION) { 305 pfsyncstats.pfsyncs_badver++; 306 goto done; 307 } 308 309 action = ph->action; 310 count = ph->count; 311 312 /* make sure it's a valid action code */ 313 if (action >= PFSYNC_ACT_MAX) { 314 pfsyncstats.pfsyncs_badact++; 315 goto done; 316 } 317 318 /* Cheaper to grab this now than having to mess with mbufs later */ 319 src = ip->ip_src; 320 321 switch (action) { 322 case PFSYNC_ACT_CLR: { 323 struct pfi_kif *kif; 324 u_int32_t creatorid; 325 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 326 sizeof(*cp), &offp)) == NULL) { 327 pfsyncstats.pfsyncs_badlen++; 328 return; 329 } 330 cp = (struct pfsync_state_clr *)(mp->m_data + offp); 331 creatorid = cp->creatorid; 332 333 crit_enter(); 334 if (cp->ifname[0] == '\0') { 335 RB_FOREACH(st, pf_state_tree_id, &tree_id) { 336 if (st->creatorid == creatorid) 337 st->timeout = PFTM_PURGE; 338 } 339 } else { 340 kif = pfi_lookup_if(cp->ifname); 341 if (kif == NULL) { 342 if (pf_status.debug >= PF_DEBUG_MISC) 343 printf("pfsync_input: PFSYNC_ACT_CLR " 344 "bad interface: %s\n", cp->ifname); 345 crit_exit(); 346 goto done; 347 } 348 RB_FOREACH(st, pf_state_tree_lan_ext, 349 &kif->pfik_lan_ext) { 350 if (st->creatorid == creatorid) 351 st->timeout = PFTM_PURGE; 352 } 353 } 354 pf_purge_expired_states(); 355 crit_exit(); 356 357 break; 358 } 359 case PFSYNC_ACT_INS: 360 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 361 count * sizeof(*sp), &offp)) == NULL) { 362 pfsyncstats.pfsyncs_badlen++; 363 return; 364 } 365 366 crit_enter(); 367 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 368 i < count; i++, sp++) { 369 /* check for invalid values */ 370 if (sp->timeout >= PFTM_MAX || 371 sp->src.state > PF_TCPS_PROXY_DST || 372 sp->dst.state > PF_TCPS_PROXY_DST || 373 sp->direction > PF_OUT || 374 (sp->af != AF_INET && sp->af != AF_INET6)) { 375 if (pf_status.debug >= PF_DEBUG_MISC) 376 printf("pfsync_insert: PFSYNC_ACT_INS: " 377 "invalid value\n"); 378 pfsyncstats.pfsyncs_badstate++; 379 continue; 380 } 381 382 if ((error = pfsync_insert_net_state(sp))) { 383 if (error == ENOMEM) { 384 crit_exit(); 385 goto done; 386 } 387 continue; 388 } 389 } 390 crit_exit(); 391 break; 392 case PFSYNC_ACT_UPD: 393 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 394 count * sizeof(*sp), &offp)) == NULL) { 395 pfsyncstats.pfsyncs_badlen++; 396 return; 397 } 398 399 crit_enter(); 400 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 401 i < count; i++, sp++) { 402 /* check for invalid values */ 403 if (sp->timeout >= PFTM_MAX || 404 sp->src.state > PF_TCPS_PROXY_DST || 405 sp->dst.state > PF_TCPS_PROXY_DST) { 406 if (pf_status.debug >= PF_DEBUG_MISC) 407 printf("pfsync_insert: PFSYNC_ACT_UPD: " 408 "invalid value\n"); 409 pfsyncstats.pfsyncs_badstate++; 410 continue; 411 } 412 413 bcopy(sp->id, &key.id, sizeof(key.id)); 414 key.creatorid = sp->creatorid; 415 416 st = pf_find_state_byid(&key); 417 if (st == NULL) { 418 /* insert the update */ 419 if (pfsync_insert_net_state(sp)) 420 pfsyncstats.pfsyncs_badstate++; 421 continue; 422 } 423 pf_state_peer_ntoh(&sp->src, &st->src); 424 pf_state_peer_ntoh(&sp->dst, &st->dst); 425 st->expire = ntohl(sp->expire) + time_second; 426 st->timeout = sp->timeout; 427 428 } 429 crit_exit(); 430 break; 431 /* 432 * It's not strictly necessary for us to support the "uncompressed" 433 * delete action, but it's relatively simple and maintains consistency. 434 */ 435 case PFSYNC_ACT_DEL: 436 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 437 count * sizeof(*sp), &offp)) == NULL) { 438 pfsyncstats.pfsyncs_badlen++; 439 return; 440 } 441 442 crit_enter(); 443 for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); 444 i < count; i++, sp++) { 445 bcopy(sp->id, &key.id, sizeof(key.id)); 446 key.creatorid = sp->creatorid; 447 448 st = pf_find_state_byid(&key); 449 if (st == NULL) { 450 pfsyncstats.pfsyncs_badstate++; 451 continue; 452 } 453 /* 454 * XXX 455 * pf_purge_expired_states() is expensive, 456 * we really want to purge the state directly. 457 */ 458 st->timeout = PFTM_PURGE; 459 st->sync_flags |= PFSTATE_FROMSYNC; 460 } 461 pf_purge_expired_states(); 462 crit_exit(); 463 break; 464 case PFSYNC_ACT_UPD_C: { 465 int update_requested = 0; 466 467 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 468 count * sizeof(*up), &offp)) == NULL) { 469 pfsyncstats.pfsyncs_badlen++; 470 return; 471 } 472 473 crit_enter(); 474 for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp); 475 i < count; i++, up++) { 476 /* check for invalid values */ 477 if (up->timeout >= PFTM_MAX || 478 up->src.state > PF_TCPS_PROXY_DST || 479 up->dst.state > PF_TCPS_PROXY_DST) { 480 if (pf_status.debug >= PF_DEBUG_MISC) 481 printf("pfsync_insert: " 482 "PFSYNC_ACT_UPD_C: " 483 "invalid value\n"); 484 pfsyncstats.pfsyncs_badstate++; 485 continue; 486 } 487 488 bcopy(up->id, &key.id, sizeof(key.id)); 489 key.creatorid = up->creatorid; 490 491 st = pf_find_state_byid(&key); 492 if (st == NULL) { 493 /* We don't have this state. Ask for it. */ 494 pfsync_request_update(up, &src); 495 update_requested = 1; 496 pfsyncstats.pfsyncs_badstate++; 497 continue; 498 } 499 pf_state_peer_ntoh(&up->src, &st->src); 500 pf_state_peer_ntoh(&up->dst, &st->dst); 501 st->expire = ntohl(up->expire) + time_second; 502 st->timeout = up->timeout; 503 } 504 if (update_requested) 505 pfsync_sendout(sc); 506 crit_exit(); 507 break; 508 } 509 case PFSYNC_ACT_DEL_C: 510 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 511 count * sizeof(*dp), &offp)) == NULL) { 512 pfsyncstats.pfsyncs_badlen++; 513 return; 514 } 515 516 crit_enter(); 517 for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp); 518 i < count; i++, dp++) { 519 bcopy(dp->id, &key.id, sizeof(key.id)); 520 key.creatorid = dp->creatorid; 521 522 st = pf_find_state_byid(&key); 523 if (st == NULL) { 524 pfsyncstats.pfsyncs_badstate++; 525 continue; 526 } 527 /* 528 * XXX 529 * pf_purge_expired_states() is expensive, 530 * we really want to purge the state directly. 531 */ 532 st->timeout = PFTM_PURGE; 533 st->sync_flags |= PFSTATE_FROMSYNC; 534 } 535 pf_purge_expired_states(); 536 crit_exit(); 537 break; 538 case PFSYNC_ACT_INS_F: 539 case PFSYNC_ACT_DEL_F: 540 /* not implemented */ 541 break; 542 case PFSYNC_ACT_UREQ: 543 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 544 count * sizeof(*rup), &offp)) == NULL) { 545 pfsyncstats.pfsyncs_badlen++; 546 return; 547 } 548 549 crit_enter(); 550 /* XXX send existing. pfsync_pack_state should handle this. */ 551 if (sc->sc_mbuf != NULL) 552 pfsync_sendout(sc); 553 for (i = 0, 554 rup = (struct pfsync_state_upd_req *)(mp->m_data + offp); 555 i < count; i++, rup++) { 556 bcopy(rup->id, &key.id, sizeof(key.id)); 557 key.creatorid = rup->creatorid; 558 559 if (key.id == 0 && key.creatorid == 0) { 560 sc->sc_ureq_received = mycpu->gd_time_seconds; 561 if (pf_status.debug >= PF_DEBUG_MISC) 562 printf("pfsync: received " 563 "bulk update request\n"); 564 pfsync_send_bus(sc, PFSYNC_BUS_START); 565 callout_reset(&sc->sc_bulk_tmo, 1 * hz, 566 pfsync_bulk_update, 567 LIST_FIRST(&pfsync_list)); 568 } else { 569 st = pf_find_state_byid(&key); 570 if (st == NULL) { 571 pfsyncstats.pfsyncs_badstate++; 572 continue; 573 } 574 pfsync_pack_state(PFSYNC_ACT_UPD, st, 0); 575 } 576 } 577 if (sc->sc_mbuf != NULL) 578 pfsync_sendout(sc); 579 crit_exit(); 580 break; 581 case PFSYNC_ACT_BUS: 582 /* If we're not waiting for a bulk update, who cares. */ 583 if (sc->sc_ureq_sent == 0) 584 break; 585 586 if ((mp = m_pulldown(m, iplen + sizeof(*ph), 587 sizeof(*bus), &offp)) == NULL) { 588 pfsyncstats.pfsyncs_badlen++; 589 return; 590 } 591 bus = (struct pfsync_state_bus *)(mp->m_data + offp); 592 switch (bus->status) { 593 case PFSYNC_BUS_START: 594 callout_reset(&sc->sc_bulkfail_tmo, 595 pf_pool_limits[PF_LIMIT_STATES].limit / 596 (PFSYNC_BULKPACKETS * sc->sc_maxcount), 597 pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 598 if (pf_status.debug >= PF_DEBUG_MISC) 599 printf("pfsync: received bulk " 600 "update start\n"); 601 break; 602 case PFSYNC_BUS_END: 603 if (mycpu->gd_time_seconds - ntohl(bus->endtime) >= 604 sc->sc_ureq_sent) { 605 /* that's it, we're happy */ 606 sc->sc_ureq_sent = 0; 607 sc->sc_bulk_tries = 0; 608 callout_stop(&sc->sc_bulkfail_tmo); 609 pfsync_sync_ok = 1; 610 if (pf_status.debug >= PF_DEBUG_MISC) 611 printf("pfsync: received valid " 612 "bulk update end\n"); 613 } else { 614 if (pf_status.debug >= PF_DEBUG_MISC) 615 printf("pfsync: received invalid " 616 "bulk update end: bad timestamp\n"); 617 } 618 break; 619 } 620 break; 621 } 622 623 done: 624 if (m) 625 m_freem(m); 626 } 627 628 int 629 pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 630 struct rtentry *rt) 631 { 632 m_freem(m); 633 return (0); 634 } 635 636 /* ARGSUSED */ 637 int 638 pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 639 { 640 struct pfsync_softc *sc = ifp->if_softc; 641 struct ifreq *ifr = (struct ifreq *)data; 642 struct ip_moptions *imo = &sc->sc_imo; 643 struct pfsyncreq pfsyncr; 644 struct ifnet *sifp; 645 int error; 646 647 switch (cmd) { 648 case SIOCSIFADDR: 649 case SIOCAIFADDR: 650 case SIOCSIFDSTADDR: 651 case SIOCSIFFLAGS: 652 if (ifp->if_flags & IFF_UP) 653 ifp->if_flags |= IFF_RUNNING; 654 else 655 ifp->if_flags &= ~IFF_RUNNING; 656 break; 657 case SIOCSIFMTU: 658 if (ifr->ifr_mtu < PFSYNC_MINMTU) 659 return (EINVAL); 660 if (ifr->ifr_mtu > MCLBYTES) 661 ifr->ifr_mtu = MCLBYTES; 662 crit_enter(); 663 if (ifr->ifr_mtu < ifp->if_mtu) 664 pfsync_sendout(sc); 665 pfsync_setmtu(sc, ifr->ifr_mtu); 666 crit_exit(); 667 break; 668 case SIOCGETPFSYNC: 669 bzero(&pfsyncr, sizeof(pfsyncr)); 670 if (sc->sc_sync_ifp) 671 strlcpy(pfsyncr.pfsyncr_syncif, 672 sc->sc_sync_ifp->if_xname, IFNAMSIZ); 673 pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 674 if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)))) 675 return (error); 676 break; 677 case SIOCSETPFSYNC: 678 if ((error = suser_cred(cr, NULL_CRED_OKAY)) != 0) 679 return (error); 680 if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 681 return (error); 682 683 if (pfsyncr.pfsyncr_maxupdates > 255) 684 return (EINVAL); 685 sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 686 687 if (pfsyncr.pfsyncr_syncif[0] == 0) { 688 sc->sc_sync_ifp = NULL; 689 if (sc->sc_mbuf_net != NULL) { 690 /* Don't keep stale pfsync packets around. */ 691 crit_enter(); 692 m_freem(sc->sc_mbuf_net); 693 sc->sc_mbuf_net = NULL; 694 sc->sc_statep_net.s = NULL; 695 crit_exit(); 696 } 697 break; 698 } 699 if ((sifp = ifunit(pfsyncr.pfsyncr_syncif)) == NULL) 700 return (EINVAL); 701 else if (sifp == sc->sc_sync_ifp) 702 break; 703 704 crit_enter(); 705 if (sifp->if_mtu < sc->sc_if.if_mtu || 706 (sc->sc_sync_ifp != NULL && 707 sifp->if_mtu < sc->sc_sync_ifp->if_mtu) || 708 sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 709 pfsync_sendout(sc); 710 sc->sc_sync_ifp = sifp; 711 712 pfsync_setmtu(sc, sc->sc_if.if_mtu); 713 714 if (imo->imo_num_memberships > 0) { 715 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 716 imo->imo_multicast_ifp = NULL; 717 } 718 719 if (sc->sc_sync_ifp) { 720 struct in_addr addr; 721 722 addr.s_addr = htonl(INADDR_PFSYNC_GROUP); 723 /* XXX do we only use one group? Also see above */ 724 if ((imo->imo_membership[0] = 725 in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) { 726 crit_exit(); 727 return (ENOBUFS); 728 } 729 imo->imo_num_memberships++; 730 imo->imo_multicast_ifp = sc->sc_sync_ifp; 731 imo->imo_multicast_ttl = PFSYNC_DFLTTL; 732 imo->imo_multicast_loop = 0; 733 734 /* Request a full state table update. */ 735 sc->sc_ureq_sent = mycpu->gd_time_seconds; 736 pfsync_sync_ok = 0; 737 if (pf_status.debug >= PF_DEBUG_MISC) 738 printf("pfsync: requesting bulk update\n"); 739 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 740 pfsync_bulkfail, LIST_FIRST(&pfsync_list)); 741 pfsync_request_update(NULL, NULL); 742 pfsync_sendout(sc); 743 } 744 crit_exit(); 745 746 break; 747 748 default: 749 return (ENOTTY); 750 } 751 752 return (0); 753 } 754 755 void 756 pfsync_setmtu(struct pfsync_softc *sc, int mtu_req) 757 { 758 int mtu; 759 760 if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req) 761 mtu = sc->sc_sync_ifp->if_mtu; 762 else 763 mtu = mtu_req; 764 765 sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) / 766 sizeof(struct pfsync_state); 767 if (sc->sc_maxcount > 254) 768 sc->sc_maxcount = 254; 769 sc->sc_if.if_mtu = sizeof(struct pfsync_header) + 770 sc->sc_maxcount * sizeof(struct pfsync_state); 771 } 772 773 struct mbuf * 774 pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) 775 { 776 struct pfsync_header *h; 777 struct mbuf *m; 778 int len; 779 780 MGETHDR(m, MB_DONTWAIT, MT_DATA); 781 if (m == NULL) { 782 sc->sc_if.if_oerrors++; 783 return (NULL); 784 } 785 786 switch (action) { 787 case PFSYNC_ACT_CLR: 788 len = sizeof(struct pfsync_header) + 789 sizeof(struct pfsync_state_clr); 790 break; 791 case PFSYNC_ACT_UPD_C: 792 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) + 793 sizeof(struct pfsync_header); 794 break; 795 case PFSYNC_ACT_DEL_C: 796 len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) + 797 sizeof(struct pfsync_header); 798 break; 799 case PFSYNC_ACT_UREQ: 800 len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) + 801 sizeof(struct pfsync_header); 802 break; 803 case PFSYNC_ACT_BUS: 804 len = sizeof(struct pfsync_header) + 805 sizeof(struct pfsync_state_bus); 806 break; 807 default: 808 len = (sc->sc_maxcount * sizeof(struct pfsync_state)) + 809 sizeof(struct pfsync_header); 810 break; 811 } 812 813 if (len > MHLEN) { 814 MCLGET(m, MB_DONTWAIT); 815 if ((m->m_flags & M_EXT) == 0) { 816 m_free(m); 817 sc->sc_if.if_oerrors++; 818 return (NULL); 819 } 820 m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1); 821 } else 822 MH_ALIGN(m, len); 823 824 m->m_pkthdr.rcvif = NULL; 825 m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header); 826 h = mtod(m, struct pfsync_header *); 827 h->version = PFSYNC_VERSION; 828 h->af = 0; 829 h->count = 0; 830 h->action = action; 831 832 *sp = (void *)((char *)h + PFSYNC_HDRLEN); 833 callout_reset(&sc->sc_tmo, hz, pfsync_timeout, 834 LIST_FIRST(&pfsync_list)); 835 return (m); 836 } 837 838 int 839 pfsync_pack_state(u_int8_t action, struct pf_state *st, int compress) 840 { 841 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if; 842 struct pfsync_softc *sc = ifp->if_softc; 843 struct pfsync_header *h, *h_net; 844 struct pfsync_state *sp = NULL; 845 struct pfsync_state_upd *up = NULL; 846 struct pfsync_state_del *dp = NULL; 847 struct pf_rule *r; 848 u_long secs; 849 int ret = 0; 850 u_int8_t i = 255, newaction = 0; 851 852 /* 853 * If a packet falls in the forest and there's nobody around to 854 * hear, does it make a sound? 855 */ 856 if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL) { 857 /* Don't leave any stale pfsync packets hanging around. */ 858 if (sc->sc_mbuf != NULL) { 859 m_freem(sc->sc_mbuf); 860 sc->sc_mbuf = NULL; 861 sc->sc_statep.s = NULL; 862 } 863 return (0); 864 } 865 866 if (action >= PFSYNC_ACT_MAX) 867 return (EINVAL); 868 869 crit_enter(); 870 if (sc->sc_mbuf == NULL) { 871 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 872 (void *)&sc->sc_statep.s)) == NULL) { 873 crit_exit(); 874 return (ENOMEM); 875 } 876 h = mtod(sc->sc_mbuf, struct pfsync_header *); 877 } else { 878 h = mtod(sc->sc_mbuf, struct pfsync_header *); 879 if (h->action != action) { 880 pfsync_sendout(sc); 881 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, 882 (void *)&sc->sc_statep.s)) == NULL) { 883 crit_exit(); 884 return (ENOMEM); 885 } 886 h = mtod(sc->sc_mbuf, struct pfsync_header *); 887 } else { 888 /* 889 * If it's an update, look in the packet to see if 890 * we already have an update for the state. 891 */ 892 if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) { 893 struct pfsync_state *usp = 894 (void *)((char *)h + PFSYNC_HDRLEN); 895 896 for (i = 0; i < h->count; i++) { 897 if (!memcmp(usp->id, &st->id, 898 PFSYNC_ID_LEN) && 899 usp->creatorid == st->creatorid) { 900 sp = usp; 901 sp->updates++; 902 break; 903 } 904 usp++; 905 } 906 } 907 } 908 } 909 910 secs = time_second; 911 912 st->pfsync_time = mycpu->gd_time_seconds; 913 TAILQ_REMOVE(&state_updates, st, u.s.entry_updates); 914 TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates); 915 916 if (sp == NULL) { 917 /* not a "duplicate" update */ 918 i = 255; 919 sp = sc->sc_statep.s++; 920 sc->sc_mbuf->m_pkthdr.len = 921 sc->sc_mbuf->m_len += sizeof(struct pfsync_state); 922 h->count++; 923 bzero(sp, sizeof(*sp)); 924 925 bcopy(&st->id, sp->id, sizeof(sp->id)); 926 sp->creatorid = st->creatorid; 927 928 strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname)); 929 pf_state_host_hton(&st->lan, &sp->lan); 930 pf_state_host_hton(&st->gwy, &sp->gwy); 931 pf_state_host_hton(&st->ext, &sp->ext); 932 933 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 934 935 sp->creation = htonl(secs - st->creation); 936 sp->packets[0] = htonl(st->packets[0]); 937 sp->packets[1] = htonl(st->packets[1]); 938 sp->bytes[0] = htonl(st->bytes[0]); 939 sp->bytes[1] = htonl(st->bytes[1]); 940 if ((r = st->rule.ptr) == NULL) 941 sp->rule = htonl(-1); 942 else 943 sp->rule = htonl(r->nr); 944 if ((r = st->anchor.ptr) == NULL) 945 sp->anchor = htonl(-1); 946 else 947 sp->anchor = htonl(r->nr); 948 sp->af = st->af; 949 sp->proto = st->proto; 950 sp->direction = st->direction; 951 sp->log = st->log; 952 sp->allow_opts = st->allow_opts; 953 sp->timeout = st->timeout; 954 955 sp->sync_flags = st->sync_flags & PFSTATE_NOSYNC; 956 } 957 958 pf_state_peer_hton(&st->src, &sp->src); 959 pf_state_peer_hton(&st->dst, &sp->dst); 960 961 if (st->expire <= secs) 962 sp->expire = htonl(0); 963 else 964 sp->expire = htonl(st->expire - secs); 965 966 /* do we need to build "compressed" actions for network transfer? */ 967 if (sc->sc_sync_ifp && compress) { 968 switch (action) { 969 case PFSYNC_ACT_UPD: 970 newaction = PFSYNC_ACT_UPD_C; 971 break; 972 case PFSYNC_ACT_DEL: 973 newaction = PFSYNC_ACT_DEL_C; 974 break; 975 default: 976 /* by default we just send the uncompressed states */ 977 break; 978 } 979 } 980 981 if (newaction) { 982 if (sc->sc_mbuf_net == NULL) { 983 if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction, 984 (void *)&sc->sc_statep_net.s)) == NULL) { 985 crit_exit(); 986 return (ENOMEM); 987 } 988 } 989 h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *); 990 991 switch (newaction) { 992 case PFSYNC_ACT_UPD_C: 993 if (i != 255) { 994 up = (void *)((char *)h_net + 995 PFSYNC_HDRLEN + (i * sizeof(*up))); 996 up->updates++; 997 } else { 998 h_net->count++; 999 sc->sc_mbuf_net->m_pkthdr.len = 1000 sc->sc_mbuf_net->m_len += sizeof(*up); 1001 up = sc->sc_statep_net.u++; 1002 1003 bzero(up, sizeof(*up)); 1004 bcopy(&st->id, up->id, sizeof(up->id)); 1005 up->creatorid = st->creatorid; 1006 } 1007 up->timeout = st->timeout; 1008 up->expire = sp->expire; 1009 up->src = sp->src; 1010 up->dst = sp->dst; 1011 break; 1012 case PFSYNC_ACT_DEL_C: 1013 sc->sc_mbuf_net->m_pkthdr.len = 1014 sc->sc_mbuf_net->m_len += sizeof(*dp); 1015 dp = sc->sc_statep_net.d++; 1016 h_net->count++; 1017 1018 bzero(dp, sizeof(*dp)); 1019 bcopy(&st->id, dp->id, sizeof(dp->id)); 1020 dp->creatorid = st->creatorid; 1021 break; 1022 } 1023 } 1024 1025 if (h->count == sc->sc_maxcount || 1026 (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates))) 1027 ret = pfsync_sendout(sc); 1028 1029 crit_exit(); 1030 return (ret); 1031 } 1032 1033 /* This must be called in splnet() */ 1034 int 1035 pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) 1036 { 1037 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if; 1038 struct pfsync_header *h; 1039 struct pfsync_softc *sc = ifp->if_softc; 1040 struct pfsync_state_upd_req *rup; 1041 int ret = 0; 1042 1043 if (sc->sc_mbuf == NULL) { 1044 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1045 (void *)&sc->sc_statep.s)) == NULL) { 1046 return (ENOMEM); 1047 } 1048 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1049 } else { 1050 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1051 if (h->action != PFSYNC_ACT_UREQ) { 1052 pfsync_sendout(sc); 1053 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, 1054 (void *)&sc->sc_statep.s)) == NULL) { 1055 return (ENOMEM); 1056 } 1057 h = mtod(sc->sc_mbuf, struct pfsync_header *); 1058 } 1059 } 1060 1061 if (src != NULL) 1062 sc->sc_sendaddr = *src; 1063 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup); 1064 h->count++; 1065 rup = sc->sc_statep.r++; 1066 bzero(rup, sizeof(*rup)); 1067 if (up != NULL) { 1068 bcopy(up->id, rup->id, sizeof(rup->id)); 1069 rup->creatorid = up->creatorid; 1070 } 1071 1072 if (h->count == sc->sc_maxcount) 1073 ret = pfsync_sendout(sc); 1074 1075 return (ret); 1076 } 1077 1078 int 1079 pfsync_clear_states(u_int32_t creatorid, char *ifname) 1080 { 1081 struct ifnet *ifp = &(LIST_FIRST(&pfsync_list))->sc_if; 1082 struct pfsync_softc *sc = ifp->if_softc; 1083 struct pfsync_state_clr *cp; 1084 int ret; 1085 1086 crit_enter(); 1087 if (sc->sc_mbuf != NULL) 1088 pfsync_sendout(sc); 1089 if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR, 1090 (void *)&sc->sc_statep.c)) == NULL) { 1091 crit_exit(); 1092 return (ENOMEM); 1093 } 1094 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp); 1095 cp = sc->sc_statep.c; 1096 cp->creatorid = creatorid; 1097 if (ifname != NULL) 1098 strlcpy(cp->ifname, ifname, IFNAMSIZ); 1099 1100 ret = (pfsync_sendout(sc)); 1101 crit_exit(); 1102 return (ret); 1103 } 1104 1105 void 1106 pfsync_timeout(void *v) 1107 { 1108 struct pfsync_softc *sc = v; 1109 1110 crit_enter(); 1111 pfsync_sendout(sc); 1112 crit_exit(); 1113 } 1114 1115 void 1116 pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status) 1117 { 1118 struct pfsync_state_bus *bus; 1119 1120 if (sc->sc_mbuf != NULL) 1121 pfsync_sendout(sc); 1122 1123 if (pfsync_sync_ok && 1124 (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS, 1125 (void *)&sc->sc_statep.b)) != NULL) { 1126 sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus); 1127 bus = sc->sc_statep.b; 1128 bus->creatorid = pf_status.hostid; 1129 bus->status = status; 1130 bus->endtime = htonl(mycpu->gd_time_seconds - sc->sc_ureq_received); 1131 pfsync_sendout(sc); 1132 } 1133 } 1134 1135 void 1136 pfsync_bulk_update(void *v) 1137 { 1138 struct pfsync_softc *sc = v; 1139 int i = 0; 1140 struct pf_state *state; 1141 1142 crit_enter(); 1143 if (sc->sc_mbuf != NULL) 1144 pfsync_sendout(sc); 1145 1146 /* 1147 * Grab at most PFSYNC_BULKPACKETS worth of states which have not 1148 * been sent since the latest request was made. 1149 */ 1150 while ((state = TAILQ_FIRST(&state_updates)) != NULL && 1151 ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) { 1152 if (state->pfsync_time > sc->sc_ureq_received) { 1153 /* we're done */ 1154 pfsync_send_bus(sc, PFSYNC_BUS_END); 1155 sc->sc_ureq_received = 0; 1156 callout_stop(&sc->sc_bulk_tmo); 1157 if (pf_status.debug >= PF_DEBUG_MISC) 1158 printf("pfsync: bulk update complete\n"); 1159 break; 1160 } else { 1161 /* send an update and move to end of list */ 1162 if (!state->sync_flags) 1163 pfsync_pack_state(PFSYNC_ACT_UPD, state, 0); 1164 state->pfsync_time = mycpu->gd_time_seconds; 1165 TAILQ_REMOVE(&state_updates, state, u.s.entry_updates); 1166 TAILQ_INSERT_TAIL(&state_updates, state, 1167 u.s.entry_updates); 1168 1169 /* look again for more in a bit */ 1170 callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout, 1171 LIST_FIRST(&pfsync_list)); 1172 } 1173 } 1174 if (sc->sc_mbuf != NULL) 1175 pfsync_sendout(sc); 1176 crit_exit(); 1177 } 1178 1179 void 1180 pfsync_bulkfail(void *v) 1181 { 1182 struct pfsync_softc *sc = v; 1183 1184 if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 1185 /* Try again in a bit */ 1186 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail, 1187 LIST_FIRST(&pfsync_list)); 1188 pfsync_request_update(NULL, NULL); 1189 pfsync_sendout(sc); 1190 } else { 1191 /* Pretend like the transfer was ok */ 1192 sc->sc_ureq_sent = 0; 1193 sc->sc_bulk_tries = 0; 1194 pfsync_sync_ok = 1; 1195 if (pf_status.debug >= PF_DEBUG_MISC) 1196 printf("pfsync: failed to receive " 1197 "bulk update status\n"); 1198 callout_stop(&sc->sc_bulkfail_tmo); 1199 } 1200 } 1201 1202 int 1203 pfsync_sendout(struct pfsync_softc *sc) 1204 { 1205 struct ifnet *ifp = &sc->sc_if; 1206 struct mbuf *m; 1207 1208 callout_stop(&sc->sc_tmo); 1209 1210 if (sc->sc_mbuf == NULL) 1211 return (0); 1212 m = sc->sc_mbuf; 1213 sc->sc_mbuf = NULL; 1214 sc->sc_statep.s = NULL; 1215 1216 KASSERT(m != NULL, ("pfsync_sendout: null mbuf")); 1217 BPF_MTAP(ifp, m); 1218 1219 if (sc->sc_mbuf_net) { 1220 m_freem(m); 1221 m = sc->sc_mbuf_net; 1222 sc->sc_mbuf_net = NULL; 1223 sc->sc_statep_net.s = NULL; 1224 } 1225 1226 if (sc->sc_sync_ifp) { 1227 struct ip *ip; 1228 struct ifaddr *ifa; 1229 struct sockaddr sa; 1230 1231 M_PREPEND(m, sizeof(struct ip), MB_DONTWAIT); 1232 if (m == NULL) { 1233 pfsyncstats.pfsyncs_onomem++; 1234 return (0); 1235 } 1236 ip = mtod(m, struct ip *); 1237 ip->ip_v = IPVERSION; 1238 ip->ip_hl = sizeof(*ip) >> 2; 1239 ip->ip_tos = IPTOS_LOWDELAY; 1240 ip->ip_len = m->m_pkthdr.len; 1241 #ifdef RANDOM_IP_ID 1242 ip->ip_id = ip_randomid(); 1243 #else 1244 ip->ip_id = ntohs(ip_id++); 1245 #endif 1246 ip->ip_off = IP_DF; 1247 ip->ip_ttl = PFSYNC_DFLTTL; 1248 ip->ip_p = IPPROTO_PFSYNC; 1249 ip->ip_sum = 0; 1250 1251 bzero(&sa, sizeof(sa)); 1252 sa.sa_family = AF_INET; 1253 ifa = ifaof_ifpforaddr(&sa, sc->sc_sync_ifp); 1254 if (ifa == NULL) 1255 return (0); 1256 ip->ip_src.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr; 1257 1258 if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP)) 1259 m->m_flags |= M_MCAST; 1260 ip->ip_dst = sc->sc_sendaddr; 1261 sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); 1262 1263 pfsyncstats.pfsyncs_opackets++; 1264 1265 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) 1266 pfsyncstats.pfsyncs_oerrors++; 1267 } else 1268 m_freem(m); 1269 1270 return (0); 1271 } 1272 1273 static int 1274 pfsync_modevent(module_t mod, int type, void *data) 1275 { 1276 int error = 0; 1277 1278 switch (type) { 1279 case MOD_LOAD: 1280 LIST_INIT(&pfsync_list); 1281 if_clone_attach(&pfsync_cloner); 1282 break; 1283 1284 case MOD_UNLOAD: 1285 if_clone_detach(&pfsync_cloner); 1286 while (!LIST_EMPTY(&pfsync_list)) 1287 pfsync_clone_destroy( 1288 &LIST_FIRST(&pfsync_list)->sc_if); 1289 break; 1290 1291 default: 1292 error = EINVAL; 1293 break; 1294 } 1295 1296 return error; 1297 } 1298 1299 static moduledata_t pfsync_mod = { 1300 "pfsync", 1301 pfsync_modevent, 1302 0 1303 }; 1304 1305 #define PFSYNC_MODVER 1 1306 1307 DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 1308 MODULE_VERSION(pfsync, PFSYNC_MODVER); 1309