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