if_pfsync.c revision 226801
1/* $OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $ */ 2 3/* 4 * Copyright (c) 2002 Michael Shalayeff 5 * All rights reserved. 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 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * Copyright (c) 2009 David Gwynne <dlg@openbsd.org> 31 * 32 * Permission to use, copy, modify, and distribute this software for any 33 * purpose with or without fee is hereby granted, provided that the above 34 * copyright notice and this permission notice appear in all copies. 35 * 36 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 37 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 38 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 39 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 41 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 42 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 43 */ 44 45#ifdef __FreeBSD__ 46#include "opt_inet.h" 47#include "opt_inet6.h" 48#include "opt_bpf.h" 49#include "opt_pf.h" 50 51#include <sys/cdefs.h> 52__FBSDID("$FreeBSD: stable/9/sys/contrib/pf/net/if_pfsync.c 226801 2011-10-26 17:09:09Z glebius $"); 53 54#ifdef DEV_BPF 55#define NBPFILTER DEV_BPF 56#else 57#define NBPFILTER 0 58#endif 59 60#ifdef DEV_PFSYNC 61#define NPFSYNC DEV_PFSYNC 62#else 63#define NPFSYNC 0 64#endif 65 66#ifdef DEV_CARP 67#define NCARP DEV_CARP 68#else 69#define NCARP 0 70#endif 71#endif /* __FreeBSD__ */ 72 73#include <sys/param.h> 74#include <sys/kernel.h> 75#ifdef __FreeBSD__ 76#include <sys/bus.h> 77#include <sys/interrupt.h> 78#include <sys/priv.h> 79#endif 80#include <sys/proc.h> 81#include <sys/systm.h> 82#include <sys/time.h> 83#include <sys/mbuf.h> 84#include <sys/socket.h> 85#ifdef __FreeBSD__ 86#include <sys/endian.h> 87#include <sys/malloc.h> 88#include <sys/module.h> 89#include <sys/sockio.h> 90#include <sys/taskqueue.h> 91#include <sys/lock.h> 92#include <sys/mutex.h> 93#else 94#include <sys/ioctl.h> 95#include <sys/timeout.h> 96#endif 97#include <sys/sysctl.h> 98#ifndef __FreeBSD__ 99#include <sys/pool.h> 100#endif 101 102#include <net/if.h> 103#ifdef __FreeBSD__ 104#include <net/if_clone.h> 105#endif 106#include <net/if_types.h> 107#include <net/route.h> 108#include <net/bpf.h> 109#include <net/netisr.h> 110#ifdef __FreeBSD__ 111#include <net/vnet.h> 112#endif 113 114#include <netinet/in.h> 115#include <netinet/if_ether.h> 116#include <netinet/tcp.h> 117#include <netinet/tcp_seq.h> 118 119#ifdef INET 120#include <netinet/in_systm.h> 121#include <netinet/in_var.h> 122#include <netinet/ip.h> 123#include <netinet/ip_var.h> 124#endif 125 126#ifdef INET6 127#include <netinet6/nd6.h> 128#endif /* INET6 */ 129 130#ifndef __FreeBSD__ 131#include "carp.h" 132#endif 133#if NCARP > 0 134#include <netinet/ip_carp.h> 135#endif 136 137#include <net/pfvar.h> 138#include <net/if_pfsync.h> 139 140#ifndef __FreeBSD__ 141#include "bpfilter.h" 142#include "pfsync.h" 143#endif 144 145#define PFSYNC_MINPKT ( \ 146 sizeof(struct ip) + \ 147 sizeof(struct pfsync_header) + \ 148 sizeof(struct pfsync_subheader) + \ 149 sizeof(struct pfsync_eof)) 150 151struct pfsync_pkt { 152 struct ip *ip; 153 struct in_addr src; 154 u_int8_t flags; 155}; 156 157int pfsync_input_hmac(struct mbuf *, int); 158 159int pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *, 160 struct pfsync_state_peer *); 161 162int pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int); 163int pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int); 164int pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int); 165int pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int); 166int pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int); 167int pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int); 168int pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int); 169int pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int); 170int pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int); 171int pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int); 172int pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int); 173 174int pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int); 175 176int (*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = { 177 pfsync_in_clr, /* PFSYNC_ACT_CLR */ 178 pfsync_in_ins, /* PFSYNC_ACT_INS */ 179 pfsync_in_iack, /* PFSYNC_ACT_INS_ACK */ 180 pfsync_in_upd, /* PFSYNC_ACT_UPD */ 181 pfsync_in_upd_c, /* PFSYNC_ACT_UPD_C */ 182 pfsync_in_ureq, /* PFSYNC_ACT_UPD_REQ */ 183 pfsync_in_del, /* PFSYNC_ACT_DEL */ 184 pfsync_in_del_c, /* PFSYNC_ACT_DEL_C */ 185 pfsync_in_error, /* PFSYNC_ACT_INS_F */ 186 pfsync_in_error, /* PFSYNC_ACT_DEL_F */ 187 pfsync_in_bus, /* PFSYNC_ACT_BUS */ 188 pfsync_in_tdb, /* PFSYNC_ACT_TDB */ 189 pfsync_in_eof /* PFSYNC_ACT_EOF */ 190}; 191 192struct pfsync_q { 193 int (*write)(struct pf_state *, struct mbuf *, int); 194 size_t len; 195 u_int8_t action; 196}; 197 198/* we have one of these for every PFSYNC_S_ */ 199int pfsync_out_state(struct pf_state *, struct mbuf *, int); 200int pfsync_out_iack(struct pf_state *, struct mbuf *, int); 201int pfsync_out_upd_c(struct pf_state *, struct mbuf *, int); 202int pfsync_out_del(struct pf_state *, struct mbuf *, int); 203 204struct pfsync_q pfsync_qs[] = { 205 { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_INS }, 206 { pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK }, 207 { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_UPD }, 208 { pfsync_out_upd_c, sizeof(struct pfsync_upd_c), PFSYNC_ACT_UPD_C }, 209 { pfsync_out_del, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C } 210}; 211 212void pfsync_q_ins(struct pf_state *, int); 213void pfsync_q_del(struct pf_state *); 214 215struct pfsync_upd_req_item { 216 TAILQ_ENTRY(pfsync_upd_req_item) ur_entry; 217 struct pfsync_upd_req ur_msg; 218}; 219TAILQ_HEAD(pfsync_upd_reqs, pfsync_upd_req_item); 220 221struct pfsync_deferral { 222 TAILQ_ENTRY(pfsync_deferral) pd_entry; 223 struct pf_state *pd_st; 224 struct mbuf *pd_m; 225#ifdef __FreeBSD__ 226 struct callout pd_tmo; 227#else 228 struct timeout pd_tmo; 229#endif 230}; 231TAILQ_HEAD(pfsync_deferrals, pfsync_deferral); 232 233#define PFSYNC_PLSIZE MAX(sizeof(struct pfsync_upd_req_item), \ 234 sizeof(struct pfsync_deferral)) 235 236#ifdef notyet 237int pfsync_out_tdb(struct tdb *, struct mbuf *, int); 238#endif 239 240struct pfsync_softc { 241#ifdef __FreeBSD__ 242 struct ifnet *sc_ifp; 243#else 244 struct ifnet sc_if; 245#endif 246 struct ifnet *sc_sync_if; 247 248#ifdef __FreeBSD__ 249 uma_zone_t sc_pool; 250#else 251 struct pool sc_pool; 252#endif 253 254 struct ip_moptions sc_imo; 255 256 struct in_addr sc_sync_peer; 257 u_int8_t sc_maxupdates; 258#ifdef __FreeBSD__ 259 int pfsync_sync_ok; 260#endif 261 262 struct ip sc_template; 263 264 struct pf_state_queue sc_qs[PFSYNC_S_COUNT]; 265 size_t sc_len; 266 267 struct pfsync_upd_reqs sc_upd_req_list; 268 269 struct pfsync_deferrals sc_deferrals; 270 u_int sc_deferred; 271 272 void *sc_plus; 273 size_t sc_pluslen; 274 275 u_int32_t sc_ureq_sent; 276 int sc_bulk_tries; 277#ifdef __FreeBSD__ 278 struct callout sc_bulkfail_tmo; 279#else 280 struct timeout sc_bulkfail_tmo; 281#endif 282 283 u_int32_t sc_ureq_received; 284 struct pf_state *sc_bulk_next; 285 struct pf_state *sc_bulk_last; 286#ifdef __FreeBSD__ 287 struct callout sc_bulk_tmo; 288#else 289 struct timeout sc_bulk_tmo; 290#endif 291 292 TAILQ_HEAD(, tdb) sc_tdb_q; 293 294#ifdef __FreeBSD__ 295 struct callout sc_tmo; 296#else 297 struct timeout sc_tmo; 298#endif 299#ifdef __FreeBSD__ 300 eventhandler_tag sc_detachtag; 301#endif 302 303}; 304 305#ifdef __FreeBSD__ 306static VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; 307#define V_pfsyncif VNET(pfsyncif) 308 309static VNET_DEFINE(struct pfsyncstats, pfsyncstats); 310#define V_pfsyncstats VNET(pfsyncstats) 311 312SYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC"); 313SYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW, 314 &VNET_NAME(pfsyncstats), pfsyncstats, 315 "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 316#else 317struct pfsync_softc *pfsyncif = NULL; 318struct pfsyncstats pfsyncstats; 319#define V_pfsyncstats pfsyncstats 320#endif 321 322#ifdef __FreeBSD__ 323static void pfsyncintr(void *); 324struct pfsync_swi { 325 void * pfsync_swi_cookie; 326}; 327static struct pfsync_swi pfsync_swi; 328#define schednetisr(p) swi_sched(pfsync_swi.pfsync_swi_cookie, 0) 329#define NETISR_PFSYNC 330#endif 331 332void pfsyncattach(int); 333#ifdef __FreeBSD__ 334int pfsync_clone_create(struct if_clone *, int, caddr_t); 335void pfsync_clone_destroy(struct ifnet *); 336#else 337int pfsync_clone_create(struct if_clone *, int); 338int pfsync_clone_destroy(struct ifnet *); 339#endif 340int pfsync_alloc_scrub_memory(struct pfsync_state_peer *, 341 struct pf_state_peer *); 342void pfsync_update_net_tdb(struct pfsync_tdb *); 343int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 344#ifdef __FreeBSD__ 345 struct route *); 346#else 347 struct rtentry *); 348#endif 349int pfsyncioctl(struct ifnet *, u_long, caddr_t); 350void pfsyncstart(struct ifnet *); 351 352struct mbuf *pfsync_if_dequeue(struct ifnet *); 353struct mbuf *pfsync_get_mbuf(struct pfsync_softc *); 354 355void pfsync_deferred(struct pf_state *, int); 356void pfsync_undefer(struct pfsync_deferral *, int); 357void pfsync_defer_tmo(void *); 358 359void pfsync_request_update(u_int32_t, u_int64_t); 360void pfsync_update_state_req(struct pf_state *); 361 362void pfsync_drop(struct pfsync_softc *); 363void pfsync_sendout(void); 364void pfsync_send_plus(void *, size_t); 365int pfsync_tdb_sendout(struct pfsync_softc *); 366int pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *); 367void pfsync_timeout(void *); 368void pfsync_tdb_timeout(void *); 369void pfsync_send_bus(struct pfsync_softc *, u_int8_t); 370 371void pfsync_bulk_start(void); 372void pfsync_bulk_status(u_int8_t); 373void pfsync_bulk_update(void *); 374void pfsync_bulk_fail(void *); 375 376#ifdef __FreeBSD__ 377void pfsync_ifdetach(void *, struct ifnet *); 378 379/* XXX: ugly */ 380#define betoh64 (unsigned long long)be64toh 381#define timeout_del callout_stop 382#endif 383 384#define PFSYNC_MAX_BULKTRIES 12 385#ifndef __FreeBSD__ 386int pfsync_sync_ok; 387#endif 388 389#ifdef __FreeBSD__ 390IFC_SIMPLE_DECLARE(pfsync, 1); 391#else 392struct if_clone pfsync_cloner = 393 IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy); 394#endif 395 396void 397pfsyncattach(int npfsync) 398{ 399 if_clone_attach(&pfsync_cloner); 400} 401int 402#ifdef __FreeBSD__ 403pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) 404#else 405pfsync_clone_create(struct if_clone *ifc, int unit) 406#endif 407{ 408 struct pfsync_softc *sc; 409 struct ifnet *ifp; 410 int q; 411 412 if (unit != 0) 413 return (EINVAL); 414 415#ifndef __FreeBSD__ 416 pfsync_sync_ok = 1; 417#endif 418 419 sc = malloc(sizeof(struct pfsync_softc), M_DEVBUF, M_NOWAIT | M_ZERO); 420 if (sc == NULL) 421 return (ENOMEM); 422 423 for (q = 0; q < PFSYNC_S_COUNT; q++) 424 TAILQ_INIT(&sc->sc_qs[q]); 425 426#ifdef __FreeBSD__ 427 sc->pfsync_sync_ok = 1; 428 sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE, 429 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 430 if (sc->sc_pool == NULL) { 431 free(sc, M_DEVBUF); 432 return (ENOMEM); 433 } 434#else 435 pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL); 436#endif 437 TAILQ_INIT(&sc->sc_upd_req_list); 438 TAILQ_INIT(&sc->sc_deferrals); 439 sc->sc_deferred = 0; 440 441 TAILQ_INIT(&sc->sc_tdb_q); 442 443 sc->sc_len = PFSYNC_MINPKT; 444 sc->sc_maxupdates = 128; 445 446#ifdef __FreeBSD__ 447 sc->sc_imo.imo_membership = (struct in_multi **)malloc( 448 (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_DEVBUF, 449 M_NOWAIT | M_ZERO); 450 sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 451 sc->sc_imo.imo_multicast_vif = -1; 452#else 453 sc->sc_imo.imo_membership = (struct in_multi **)malloc( 454 (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS, 455 M_WAITOK | M_ZERO); 456 sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; 457#endif 458 459#ifdef __FreeBSD__ 460 ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 461 if (ifp == NULL) { 462 free(sc->sc_imo.imo_membership, M_DEVBUF); 463 uma_zdestroy(sc->sc_pool); 464 free(sc, M_DEVBUF); 465 return (ENOSPC); 466 } 467 if_initname(ifp, ifc->ifc_name, unit); 468 469 sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event, 470#ifdef __FreeBSD__ 471 pfsync_ifdetach, V_pfsyncif, EVENTHANDLER_PRI_ANY); 472#else 473 pfsync_ifdetach, pfsyncif, EVENTHANDLER_PRI_ANY); 474#endif 475 if (sc->sc_detachtag == NULL) { 476 if_free(ifp); 477 free(sc->sc_imo.imo_membership, M_DEVBUF); 478 uma_zdestroy(sc->sc_pool); 479 free(sc, M_DEVBUF); 480 return (ENOSPC); 481 } 482#else 483 ifp = &sc->sc_if; 484 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit); 485#endif 486 ifp->if_softc = sc; 487 ifp->if_ioctl = pfsyncioctl; 488 ifp->if_output = pfsyncoutput; 489 ifp->if_start = pfsyncstart; 490 ifp->if_type = IFT_PFSYNC; 491 ifp->if_snd.ifq_maxlen = ifqmaxlen; 492 ifp->if_hdrlen = sizeof(struct pfsync_header); 493 ifp->if_mtu = 1500; /* XXX */ 494#ifdef __FreeBSD__ 495 callout_init(&sc->sc_tmo, CALLOUT_MPSAFE); 496 callout_init_mtx(&sc->sc_bulk_tmo, &pf_task_mtx, 0); 497 callout_init(&sc->sc_bulkfail_tmo, CALLOUT_MPSAFE); 498#else 499 ifp->if_hardmtu = MCLBYTES; /* XXX */ 500 timeout_set(&sc->sc_tmo, pfsync_timeout, sc); 501 timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc); 502 timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc); 503#endif 504 505 if_attach(ifp); 506#ifndef __FreeBSD__ 507 if_alloc_sadl(ifp); 508#endif 509 510#if NCARP > 0 511 if_addgroup(ifp, "carp"); 512#endif 513 514#if NBPFILTER > 0 515#ifdef __FreeBSD__ 516 bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 517#else 518 bpfattach(&sc->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 519#endif 520#endif 521 522#ifdef __FreeBSD__ 523 V_pfsyncif = sc; 524#else 525 pfsyncif = sc; 526#endif 527 528 return (0); 529} 530 531#ifdef __FreeBSD__ 532void 533#else 534int 535#endif 536pfsync_clone_destroy(struct ifnet *ifp) 537{ 538 struct pfsync_softc *sc = ifp->if_softc; 539 540#ifdef __FreeBSD__ 541 EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag); 542#endif 543 timeout_del(&sc->sc_bulk_tmo); /* XXX: need PF_LOCK() before */ 544 timeout_del(&sc->sc_tmo); 545#if NCARP > 0 546#ifdef notyet 547#ifdef __FreeBSD__ 548 if (!sc->pfsync_sync_ok) 549#else 550 if (!pfsync_sync_ok) 551#endif 552 carp_group_demote_adj(&sc->sc_if, -1); 553#endif 554#endif 555#if NBPFILTER > 0 556 bpfdetach(ifp); 557#endif 558 if_detach(ifp); 559 560 pfsync_drop(sc); 561 562 while (sc->sc_deferred > 0) 563 pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 564 565#ifdef __FreeBSD__ 566 UMA_DESTROY(sc->sc_pool); 567#else 568 pool_destroy(&sc->sc_pool); 569#endif 570#ifdef __FreeBSD__ 571 if_free(ifp); 572 free(sc->sc_imo.imo_membership, M_DEVBUF); 573#else 574 free(sc->sc_imo.imo_membership, M_IPMOPTS); 575#endif 576 free(sc, M_DEVBUF); 577 578#ifdef __FreeBSD__ 579 V_pfsyncif = NULL; 580#else 581 pfsyncif = NULL; 582#endif 583 584#ifndef __FreeBSD__ 585 return (0); 586#endif 587} 588 589struct mbuf * 590pfsync_if_dequeue(struct ifnet *ifp) 591{ 592 struct mbuf *m; 593#ifndef __FreeBSD__ 594 int s; 595#endif 596 597#ifdef __FreeBSD__ 598 IF_LOCK(&ifp->if_snd); 599 _IF_DROP(&ifp->if_snd); 600 _IF_DEQUEUE(&ifp->if_snd, m); 601 IF_UNLOCK(&ifp->if_snd); 602#else 603 s = splnet(); 604 IF_DEQUEUE(&ifp->if_snd, m); 605 splx(s); 606#endif 607 608 return (m); 609} 610 611/* 612 * Start output on the pfsync interface. 613 */ 614void 615pfsyncstart(struct ifnet *ifp) 616{ 617 struct mbuf *m; 618 619 while ((m = pfsync_if_dequeue(ifp)) != NULL) { 620#ifndef __FreeBSD__ 621 IF_DROP(&ifp->if_snd); 622#endif 623 m_freem(m); 624 } 625} 626 627int 628pfsync_alloc_scrub_memory(struct pfsync_state_peer *s, 629 struct pf_state_peer *d) 630{ 631 if (s->scrub.scrub_flag && d->scrub == NULL) { 632#ifdef __FreeBSD__ 633 d->scrub = pool_get(&V_pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); 634#else 635 d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); 636#endif 637 if (d->scrub == NULL) 638 return (ENOMEM); 639 } 640 641 return (0); 642} 643 644#ifndef __FreeBSD__ 645void 646pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) 647{ 648 bzero(sp, sizeof(struct pfsync_state)); 649 650 /* copy from state key */ 651 sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; 652 sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; 653 sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; 654 sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; 655 sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; 656 sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; 657 sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; 658 sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; 659 sp->proto = st->key[PF_SK_WIRE]->proto; 660 sp->af = st->key[PF_SK_WIRE]->af; 661 662 /* copy from state */ 663 strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); 664 bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); 665 sp->creation = htonl(time_second - st->creation); 666 sp->expire = pf_state_expires(st); 667 if (sp->expire <= time_second) 668 sp->expire = htonl(0); 669 else 670 sp->expire = htonl(sp->expire - time_second); 671 672 sp->direction = st->direction; 673 sp->log = st->log; 674 sp->timeout = st->timeout; 675 sp->state_flags = st->state_flags; 676 if (st->src_node) 677 sp->sync_flags |= PFSYNC_FLAG_SRCNODE; 678 if (st->nat_src_node) 679 sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; 680 681 bcopy(&st->id, &sp->id, sizeof(sp->id)); 682 sp->creatorid = st->creatorid; 683 pf_state_peer_hton(&st->src, &sp->src); 684 pf_state_peer_hton(&st->dst, &sp->dst); 685 686 if (st->rule.ptr == NULL) 687 sp->rule = htonl(-1); 688 else 689 sp->rule = htonl(st->rule.ptr->nr); 690 if (st->anchor.ptr == NULL) 691 sp->anchor = htonl(-1); 692 else 693 sp->anchor = htonl(st->anchor.ptr->nr); 694 if (st->nat_rule.ptr == NULL) 695 sp->nat_rule = htonl(-1); 696 else 697 sp->nat_rule = htonl(st->nat_rule.ptr->nr); 698 699 pf_state_counter_hton(st->packets[0], sp->packets[0]); 700 pf_state_counter_hton(st->packets[1], sp->packets[1]); 701 pf_state_counter_hton(st->bytes[0], sp->bytes[0]); 702 pf_state_counter_hton(st->bytes[1], sp->bytes[1]); 703 704} 705#endif 706 707int 708pfsync_state_import(struct pfsync_state *sp, u_int8_t flags) 709{ 710 struct pf_state *st = NULL; 711 struct pf_state_key *skw = NULL, *sks = NULL; 712 struct pf_rule *r = NULL; 713 struct pfi_kif *kif; 714 int pool_flags; 715 int error; 716 717 PF_LOCK_ASSERT(); 718 719#ifdef __FreeBSD__ 720 if (sp->creatorid == 0 && V_pf_status.debug >= PF_DEBUG_MISC) { 721#else 722 if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { 723#endif 724 printf("pfsync_state_import: invalid creator id:" 725 " %08x\n", ntohl(sp->creatorid)); 726 return (EINVAL); 727 } 728 729 if ((kif = pfi_kif_get(sp->ifname)) == NULL) { 730#ifdef __FreeBSD__ 731 if (V_pf_status.debug >= PF_DEBUG_MISC) 732#else 733 if (pf_status.debug >= PF_DEBUG_MISC) 734#endif 735 printf("pfsync_state_import: " 736 "unknown interface: %s\n", sp->ifname); 737 if (flags & PFSYNC_SI_IOCTL) 738 return (EINVAL); 739 return (0); /* skip this state */ 740 } 741 742 /* 743 * If the ruleset checksums match or the state is coming from the ioctl, 744 * it's safe to associate the state with the rule of that number. 745 */ 746 if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && 747 (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < 748 pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) 749 r = pf_main_ruleset.rules[ 750 PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; 751 else 752#ifdef __FreeBSD__ 753 r = &V_pf_default_rule; 754#else 755 r = &pf_default_rule; 756#endif 757 758 if ((r->max_states && r->states_cur >= r->max_states)) 759 goto cleanup; 760 761#ifdef __FreeBSD__ 762 if (flags & PFSYNC_SI_IOCTL) 763 pool_flags = PR_WAITOK | PR_ZERO; 764 else 765 pool_flags = PR_NOWAIT | PR_ZERO; 766 767 if ((st = pool_get(&V_pf_state_pl, pool_flags)) == NULL) 768 goto cleanup; 769#else 770 if (flags & PFSYNC_SI_IOCTL) 771 pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO; 772 else 773 pool_flags = PR_LIMITFAIL | PR_ZERO; 774 775 if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL) 776 goto cleanup; 777#endif 778 779 if ((skw = pf_alloc_state_key(pool_flags)) == NULL) 780 goto cleanup; 781 782 if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], 783 &sp->key[PF_SK_STACK].addr[0], sp->af) || 784 PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], 785 &sp->key[PF_SK_STACK].addr[1], sp->af) || 786 sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || 787 sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) { 788 if ((sks = pf_alloc_state_key(pool_flags)) == NULL) 789 goto cleanup; 790 } else 791 sks = skw; 792 793 /* allocate memory for scrub info */ 794 if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || 795 pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) 796 goto cleanup; 797 798 /* copy to state key(s) */ 799 skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; 800 skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; 801 skw->port[0] = sp->key[PF_SK_WIRE].port[0]; 802 skw->port[1] = sp->key[PF_SK_WIRE].port[1]; 803 skw->proto = sp->proto; 804 skw->af = sp->af; 805 if (sks != skw) { 806 sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; 807 sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; 808 sks->port[0] = sp->key[PF_SK_STACK].port[0]; 809 sks->port[1] = sp->key[PF_SK_STACK].port[1]; 810 sks->proto = sp->proto; 811 sks->af = sp->af; 812 } 813 814 /* copy to state */ 815 bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 816 st->creation = time_second - ntohl(sp->creation); 817 st->expire = time_second; 818 if (sp->expire) { 819 /* XXX No adaptive scaling. */ 820 st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire); 821 } 822 823 st->expire = ntohl(sp->expire) + time_second; 824 st->direction = sp->direction; 825 st->log = sp->log; 826 st->timeout = sp->timeout; 827 st->state_flags = sp->state_flags; 828 829 bcopy(sp->id, &st->id, sizeof(st->id)); 830 st->creatorid = sp->creatorid; 831 pf_state_peer_ntoh(&sp->src, &st->src); 832 pf_state_peer_ntoh(&sp->dst, &st->dst); 833 834 st->rule.ptr = r; 835 st->nat_rule.ptr = NULL; 836 st->anchor.ptr = NULL; 837 st->rt_kif = NULL; 838 839 st->pfsync_time = time_second; 840 st->sync_state = PFSYNC_S_NONE; 841 842 /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 843 r->states_cur++; 844 r->states_tot++; 845 846 if (!ISSET(flags, PFSYNC_SI_IOCTL)) 847 SET(st->state_flags, PFSTATE_NOSYNC); 848 849 if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { 850 /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 851 r->states_cur--; 852 goto cleanup_state; 853 } 854 855 if (!ISSET(flags, PFSYNC_SI_IOCTL)) { 856 CLR(st->state_flags, PFSTATE_NOSYNC); 857 if (ISSET(st->state_flags, PFSTATE_ACK)) { 858 pfsync_q_ins(st, PFSYNC_S_IACK); 859#ifdef __FreeBSD__ 860 pfsync_sendout(); 861#else 862 schednetisr(NETISR_PFSYNC); 863#endif 864 } 865 } 866 CLR(st->state_flags, PFSTATE_ACK); 867 868 return (0); 869 870cleanup: 871 error = ENOMEM; 872 if (skw == sks) 873 sks = NULL; 874#ifdef __FreeBSD__ 875 if (skw != NULL) 876 pool_put(&V_pf_state_key_pl, skw); 877 if (sks != NULL) 878 pool_put(&V_pf_state_key_pl, sks); 879#else 880 if (skw != NULL) 881 pool_put(&pf_state_key_pl, skw); 882 if (sks != NULL) 883 pool_put(&pf_state_key_pl, sks); 884#endif 885 886cleanup_state: /* pf_state_insert frees the state keys */ 887 if (st) { 888#ifdef __FreeBSD__ 889 if (st->dst.scrub) 890 pool_put(&V_pf_state_scrub_pl, st->dst.scrub); 891 if (st->src.scrub) 892 pool_put(&V_pf_state_scrub_pl, st->src.scrub); 893 pool_put(&V_pf_state_pl, st); 894#else 895 if (st->dst.scrub) 896 pool_put(&pf_state_scrub_pl, st->dst.scrub); 897 if (st->src.scrub) 898 pool_put(&pf_state_scrub_pl, st->src.scrub); 899 pool_put(&pf_state_pl, st); 900#endif 901 } 902 return (error); 903} 904 905void 906#ifdef __FreeBSD__ 907pfsync_input(struct mbuf *m, __unused int off) 908#else 909pfsync_input(struct mbuf *m, ...) 910#endif 911{ 912#ifdef __FreeBSD__ 913 struct pfsync_softc *sc = V_pfsyncif; 914#else 915 struct pfsync_softc *sc = pfsyncif; 916#endif 917 struct pfsync_pkt pkt; 918 struct ip *ip = mtod(m, struct ip *); 919 struct pfsync_header *ph; 920 struct pfsync_subheader subh; 921 922 int offset; 923 int rv; 924 925 V_pfsyncstats.pfsyncs_ipackets++; 926 927 /* verify that we have a sync interface configured */ 928#ifdef __FreeBSD__ 929 if (!sc || !sc->sc_sync_if || !V_pf_status.running) 930#else 931 if (!sc || !sc->sc_sync_if || !pf_status.running) 932#endif 933 goto done; 934 935 /* verify that the packet came in on the right interface */ 936 if (sc->sc_sync_if != m->m_pkthdr.rcvif) { 937 V_pfsyncstats.pfsyncs_badif++; 938 goto done; 939 } 940 941#ifdef __FreeBSD__ 942 sc->sc_ifp->if_ipackets++; 943 sc->sc_ifp->if_ibytes += m->m_pkthdr.len; 944#else 945 sc->sc_if.if_ipackets++; 946 sc->sc_if.if_ibytes += m->m_pkthdr.len; 947#endif 948 /* verify that the IP TTL is 255. */ 949 if (ip->ip_ttl != PFSYNC_DFLTTL) { 950 V_pfsyncstats.pfsyncs_badttl++; 951 goto done; 952 } 953 954 offset = ip->ip_hl << 2; 955 if (m->m_pkthdr.len < offset + sizeof(*ph)) { 956 V_pfsyncstats.pfsyncs_hdrops++; 957 goto done; 958 } 959 960 if (offset + sizeof(*ph) > m->m_len) { 961 if (m_pullup(m, offset + sizeof(*ph)) == NULL) { 962 V_pfsyncstats.pfsyncs_hdrops++; 963 return; 964 } 965 ip = mtod(m, struct ip *); 966 } 967 ph = (struct pfsync_header *)((char *)ip + offset); 968 969 /* verify the version */ 970 if (ph->version != PFSYNC_VERSION) { 971 V_pfsyncstats.pfsyncs_badver++; 972 goto done; 973 } 974 975#if 0 976 if (pfsync_input_hmac(m, offset) != 0) { 977 /* XXX stats */ 978 goto done; 979 } 980#endif 981 982 /* Cheaper to grab this now than having to mess with mbufs later */ 983 pkt.ip = ip; 984 pkt.src = ip->ip_src; 985 pkt.flags = 0; 986 987#ifdef __FreeBSD__ 988 if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 989#else 990 if (!bcmp(&ph->pfcksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 991#endif 992 pkt.flags |= PFSYNC_SI_CKSUM; 993 994 offset += sizeof(*ph); 995 for (;;) { 996 m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); 997 offset += sizeof(subh); 998 999 if (subh.action >= PFSYNC_ACT_MAX) { 1000 V_pfsyncstats.pfsyncs_badact++; 1001 goto done; 1002 } 1003 1004 rv = (*pfsync_acts[subh.action])(&pkt, m, offset, 1005 ntohs(subh.count)); 1006 if (rv == -1) 1007 return; 1008 1009 offset += rv; 1010 } 1011 1012done: 1013 m_freem(m); 1014} 1015 1016int 1017pfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1018{ 1019 struct pfsync_clr *clr; 1020 struct mbuf *mp; 1021 int len = sizeof(*clr) * count; 1022 int i, offp; 1023 1024 struct pf_state *st, *nexts; 1025 struct pf_state_key *sk, *nextsk; 1026 struct pf_state_item *si; 1027 u_int32_t creatorid; 1028 int s; 1029 1030 mp = m_pulldown(m, offset, len, &offp); 1031 if (mp == NULL) { 1032 V_pfsyncstats.pfsyncs_badlen++; 1033 return (-1); 1034 } 1035 clr = (struct pfsync_clr *)(mp->m_data + offp); 1036 1037 s = splsoftnet(); 1038#ifdef __FreeBSD__ 1039 PF_LOCK(); 1040#endif 1041 for (i = 0; i < count; i++) { 1042 creatorid = clr[i].creatorid; 1043 1044 if (clr[i].ifname[0] == '\0') { 1045#ifdef __FreeBSD__ 1046 for (st = RB_MIN(pf_state_tree_id, &V_tree_id); 1047 st; st = nexts) { 1048 nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, st); 1049#else 1050 for (st = RB_MIN(pf_state_tree_id, &tree_id); 1051 st; st = nexts) { 1052 nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); 1053#endif 1054 if (st->creatorid == creatorid) { 1055 SET(st->state_flags, PFSTATE_NOSYNC); 1056 pf_unlink_state(st); 1057 } 1058 } 1059 } else { 1060 if (pfi_kif_get(clr[i].ifname) == NULL) 1061 continue; 1062 1063 /* XXX correct? */ 1064#ifdef __FreeBSD__ 1065 for (sk = RB_MIN(pf_state_tree, &V_pf_statetbl); 1066#else 1067 for (sk = RB_MIN(pf_state_tree, &pf_statetbl); 1068#endif 1069 sk; sk = nextsk) { 1070 nextsk = RB_NEXT(pf_state_tree, 1071#ifdef __FreeBSD__ 1072 &V_pf_statetbl, sk); 1073#else 1074 &pf_statetbl, sk); 1075#endif 1076 TAILQ_FOREACH(si, &sk->states, entry) { 1077 if (si->s->creatorid == creatorid) { 1078 SET(si->s->state_flags, 1079 PFSTATE_NOSYNC); 1080 pf_unlink_state(si->s); 1081 } 1082 } 1083 } 1084 } 1085 } 1086#ifdef __FreeBSD__ 1087 PF_UNLOCK(); 1088#endif 1089 splx(s); 1090 1091 return (len); 1092} 1093 1094int 1095pfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1096{ 1097 struct mbuf *mp; 1098 struct pfsync_state *sa, *sp; 1099 int len = sizeof(*sp) * count; 1100 int i, offp; 1101 1102 int s; 1103 1104 mp = m_pulldown(m, offset, len, &offp); 1105 if (mp == NULL) { 1106 V_pfsyncstats.pfsyncs_badlen++; 1107 return (-1); 1108 } 1109 sa = (struct pfsync_state *)(mp->m_data + offp); 1110 1111 s = splsoftnet(); 1112#ifdef __FreeBSD__ 1113 PF_LOCK(); 1114#endif 1115 for (i = 0; i < count; i++) { 1116 sp = &sa[i]; 1117 1118 /* check for invalid values */ 1119 if (sp->timeout >= PFTM_MAX || 1120 sp->src.state > PF_TCPS_PROXY_DST || 1121 sp->dst.state > PF_TCPS_PROXY_DST || 1122 sp->direction > PF_OUT || 1123 (sp->af != AF_INET && sp->af != AF_INET6)) { 1124#ifdef __FreeBSD__ 1125 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1126#else 1127 if (pf_status.debug >= PF_DEBUG_MISC) { 1128#endif 1129 printf("pfsync_input: PFSYNC5_ACT_INS: " 1130 "invalid value\n"); 1131 } 1132 V_pfsyncstats.pfsyncs_badval++; 1133 continue; 1134 } 1135 1136 if (pfsync_state_import(sp, pkt->flags) == ENOMEM) { 1137 /* drop out, but process the rest of the actions */ 1138 break; 1139 } 1140 } 1141#ifdef __FreeBSD__ 1142 PF_UNLOCK(); 1143#endif 1144 splx(s); 1145 1146 return (len); 1147} 1148 1149int 1150pfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1151{ 1152 struct pfsync_ins_ack *ia, *iaa; 1153 struct pf_state_cmp id_key; 1154 struct pf_state *st; 1155 1156 struct mbuf *mp; 1157 int len = count * sizeof(*ia); 1158 int offp, i; 1159 int s; 1160 1161 mp = m_pulldown(m, offset, len, &offp); 1162 if (mp == NULL) { 1163 V_pfsyncstats.pfsyncs_badlen++; 1164 return (-1); 1165 } 1166 iaa = (struct pfsync_ins_ack *)(mp->m_data + offp); 1167 1168 s = splsoftnet(); 1169#ifdef __FreeBSD__ 1170 PF_LOCK(); 1171#endif 1172 for (i = 0; i < count; i++) { 1173 ia = &iaa[i]; 1174 1175 bcopy(&ia->id, &id_key.id, sizeof(id_key.id)); 1176 id_key.creatorid = ia->creatorid; 1177 1178 st = pf_find_state_byid(&id_key); 1179 if (st == NULL) 1180 continue; 1181 1182 if (ISSET(st->state_flags, PFSTATE_ACK)) 1183 pfsync_deferred(st, 0); 1184 } 1185#ifdef __FreeBSD__ 1186 PF_UNLOCK(); 1187#endif 1188 splx(s); 1189 /* 1190 * XXX this is not yet implemented, but we know the size of the 1191 * message so we can skip it. 1192 */ 1193 1194 return (count * sizeof(struct pfsync_ins_ack)); 1195} 1196 1197int 1198pfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src, 1199 struct pfsync_state_peer *dst) 1200{ 1201 int sfail = 0; 1202 1203 /* 1204 * The state should never go backwards except 1205 * for syn-proxy states. Neither should the 1206 * sequence window slide backwards. 1207 */ 1208 if (st->src.state > src->state && 1209 (st->src.state < PF_TCPS_PROXY_SRC || 1210 src->state >= PF_TCPS_PROXY_SRC)) 1211 sfail = 1; 1212 else if (SEQ_GT(st->src.seqlo, ntohl(src->seqlo))) 1213 sfail = 3; 1214 else if (st->dst.state > dst->state) { 1215 /* There might still be useful 1216 * information about the src state here, 1217 * so import that part of the update, 1218 * then "fail" so we send the updated 1219 * state back to the peer who is missing 1220 * our what we know. */ 1221 pf_state_peer_ntoh(src, &st->src); 1222 /* XXX do anything with timeouts? */ 1223 sfail = 7; 1224 } else if (st->dst.state >= TCPS_SYN_SENT && 1225 SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo))) 1226 sfail = 4; 1227 1228 return (sfail); 1229} 1230 1231int 1232pfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1233{ 1234 struct pfsync_state *sa, *sp; 1235 struct pf_state_cmp id_key; 1236 struct pf_state_key *sk; 1237 struct pf_state *st; 1238 int sfail; 1239 1240 struct mbuf *mp; 1241 int len = count * sizeof(*sp); 1242 int offp, i; 1243 int s; 1244 1245 mp = m_pulldown(m, offset, len, &offp); 1246 if (mp == NULL) { 1247 V_pfsyncstats.pfsyncs_badlen++; 1248 return (-1); 1249 } 1250 sa = (struct pfsync_state *)(mp->m_data + offp); 1251 1252 s = splsoftnet(); 1253#ifdef __FreeBSD__ 1254 PF_LOCK(); 1255#endif 1256 for (i = 0; i < count; i++) { 1257 sp = &sa[i]; 1258 1259 /* check for invalid values */ 1260 if (sp->timeout >= PFTM_MAX || 1261 sp->src.state > PF_TCPS_PROXY_DST || 1262 sp->dst.state > PF_TCPS_PROXY_DST) { 1263#ifdef __FreeBSD__ 1264 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1265#else 1266 if (pf_status.debug >= PF_DEBUG_MISC) { 1267#endif 1268 printf("pfsync_input: PFSYNC_ACT_UPD: " 1269 "invalid value\n"); 1270 } 1271 V_pfsyncstats.pfsyncs_badval++; 1272 continue; 1273 } 1274 1275 bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1276 id_key.creatorid = sp->creatorid; 1277 1278 st = pf_find_state_byid(&id_key); 1279 if (st == NULL) { 1280 /* insert the update */ 1281 if (pfsync_state_import(sp, 0)) 1282 V_pfsyncstats.pfsyncs_badstate++; 1283 continue; 1284 } 1285 1286 if (ISSET(st->state_flags, PFSTATE_ACK)) 1287 pfsync_deferred(st, 1); 1288 1289 sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1290 sfail = 0; 1291 if (sk->proto == IPPROTO_TCP) 1292 sfail = pfsync_upd_tcp(st, &sp->src, &sp->dst); 1293 else { 1294 /* 1295 * Non-TCP protocol state machine always go 1296 * forwards 1297 */ 1298 if (st->src.state > sp->src.state) 1299 sfail = 5; 1300 else if (st->dst.state > sp->dst.state) 1301 sfail = 6; 1302 } 1303 1304 if (sfail) { 1305#ifdef __FreeBSD__ 1306 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1307#else 1308 if (pf_status.debug >= PF_DEBUG_MISC) { 1309#endif 1310 printf("pfsync: %s stale update (%d)" 1311 " id: %016llx creatorid: %08x\n", 1312 (sfail < 7 ? "ignoring" : "partial"), 1313 sfail, betoh64(st->id), 1314 ntohl(st->creatorid)); 1315 } 1316 V_pfsyncstats.pfsyncs_stale++; 1317 1318 pfsync_update_state(st); 1319#ifdef __FreeBSD__ 1320 pfsync_sendout(); 1321#else 1322 schednetisr(NETISR_PFSYNC); 1323#endif 1324 continue; 1325 } 1326 pfsync_alloc_scrub_memory(&sp->dst, &st->dst); 1327 pf_state_peer_ntoh(&sp->src, &st->src); 1328 pf_state_peer_ntoh(&sp->dst, &st->dst); 1329 st->expire = ntohl(sp->expire) + time_second; 1330 st->timeout = sp->timeout; 1331 st->pfsync_time = time_second; 1332 } 1333#ifdef __FreeBSD__ 1334 PF_UNLOCK(); 1335#endif 1336 splx(s); 1337 1338 return (len); 1339} 1340 1341int 1342pfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1343{ 1344 struct pfsync_upd_c *ua, *up; 1345 struct pf_state_key *sk; 1346 struct pf_state_cmp id_key; 1347 struct pf_state *st; 1348 1349 int len = count * sizeof(*up); 1350 int sfail; 1351 1352 struct mbuf *mp; 1353 int offp, i; 1354 int s; 1355 1356 mp = m_pulldown(m, offset, len, &offp); 1357 if (mp == NULL) { 1358 V_pfsyncstats.pfsyncs_badlen++; 1359 return (-1); 1360 } 1361 ua = (struct pfsync_upd_c *)(mp->m_data + offp); 1362 1363 s = splsoftnet(); 1364#ifdef __FreeBSD__ 1365 PF_LOCK(); 1366#endif 1367 for (i = 0; i < count; i++) { 1368 up = &ua[i]; 1369 1370 /* check for invalid values */ 1371 if (up->timeout >= PFTM_MAX || 1372 up->src.state > PF_TCPS_PROXY_DST || 1373 up->dst.state > PF_TCPS_PROXY_DST) { 1374#ifdef __FreeBSD__ 1375 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1376#else 1377 if (pf_status.debug >= PF_DEBUG_MISC) { 1378#endif 1379 printf("pfsync_input: " 1380 "PFSYNC_ACT_UPD_C: " 1381 "invalid value\n"); 1382 } 1383 V_pfsyncstats.pfsyncs_badval++; 1384 continue; 1385 } 1386 1387 bcopy(&up->id, &id_key.id, sizeof(id_key.id)); 1388 id_key.creatorid = up->creatorid; 1389 1390 st = pf_find_state_byid(&id_key); 1391 if (st == NULL) { 1392 /* We don't have this state. Ask for it. */ 1393 pfsync_request_update(id_key.creatorid, id_key.id); 1394 continue; 1395 } 1396 1397 if (ISSET(st->state_flags, PFSTATE_ACK)) 1398 pfsync_deferred(st, 1); 1399 1400 sk = st->key[PF_SK_WIRE]; /* XXX right one? */ 1401 sfail = 0; 1402 if (sk->proto == IPPROTO_TCP) 1403 sfail = pfsync_upd_tcp(st, &up->src, &up->dst); 1404 else { 1405 /* 1406 * Non-TCP protocol state machine always go forwards 1407 */ 1408 if (st->src.state > up->src.state) 1409 sfail = 5; 1410 else if (st->dst.state > up->dst.state) 1411 sfail = 6; 1412 } 1413 1414 if (sfail) { 1415#ifdef __FreeBSD__ 1416 if (V_pf_status.debug >= PF_DEBUG_MISC) { 1417#else 1418 if (pf_status.debug >= PF_DEBUG_MISC) { 1419#endif 1420 printf("pfsync: ignoring stale update " 1421 "(%d) id: %016llx " 1422 "creatorid: %08x\n", sfail, 1423 betoh64(st->id), 1424 ntohl(st->creatorid)); 1425 } 1426 V_pfsyncstats.pfsyncs_stale++; 1427 1428 pfsync_update_state(st); 1429#ifdef __FreeBSD__ 1430 pfsync_sendout(); 1431#else 1432 schednetisr(NETISR_PFSYNC); 1433#endif 1434 continue; 1435 } 1436 pfsync_alloc_scrub_memory(&up->dst, &st->dst); 1437 pf_state_peer_ntoh(&up->src, &st->src); 1438 pf_state_peer_ntoh(&up->dst, &st->dst); 1439 st->expire = ntohl(up->expire) + time_second; 1440 st->timeout = up->timeout; 1441 st->pfsync_time = time_second; 1442 } 1443#ifdef __FreeBSD__ 1444 PF_UNLOCK(); 1445#endif 1446 splx(s); 1447 1448 return (len); 1449} 1450 1451int 1452pfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1453{ 1454 struct pfsync_upd_req *ur, *ura; 1455 struct mbuf *mp; 1456 int len = count * sizeof(*ur); 1457 int i, offp; 1458 1459 struct pf_state_cmp id_key; 1460 struct pf_state *st; 1461 1462 mp = m_pulldown(m, offset, len, &offp); 1463 if (mp == NULL) { 1464 V_pfsyncstats.pfsyncs_badlen++; 1465 return (-1); 1466 } 1467 ura = (struct pfsync_upd_req *)(mp->m_data + offp); 1468 1469 for (i = 0; i < count; i++) { 1470 ur = &ura[i]; 1471 1472 bcopy(&ur->id, &id_key.id, sizeof(id_key.id)); 1473 id_key.creatorid = ur->creatorid; 1474 1475 if (id_key.id == 0 && id_key.creatorid == 0) 1476 pfsync_bulk_start(); 1477 else { 1478 st = pf_find_state_byid(&id_key); 1479 if (st == NULL) { 1480 V_pfsyncstats.pfsyncs_badstate++; 1481 continue; 1482 } 1483 if (ISSET(st->state_flags, PFSTATE_NOSYNC)) 1484 continue; 1485 1486 PF_LOCK(); 1487 pfsync_update_state_req(st); 1488 PF_UNLOCK(); 1489 } 1490 } 1491 1492 return (len); 1493} 1494 1495int 1496pfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1497{ 1498 struct mbuf *mp; 1499 struct pfsync_state *sa, *sp; 1500 struct pf_state_cmp id_key; 1501 struct pf_state *st; 1502 int len = count * sizeof(*sp); 1503 int offp, i; 1504 int s; 1505 1506 mp = m_pulldown(m, offset, len, &offp); 1507 if (mp == NULL) { 1508 V_pfsyncstats.pfsyncs_badlen++; 1509 return (-1); 1510 } 1511 sa = (struct pfsync_state *)(mp->m_data + offp); 1512 1513 s = splsoftnet(); 1514#ifdef __FreeBSD__ 1515 PF_LOCK(); 1516#endif 1517 for (i = 0; i < count; i++) { 1518 sp = &sa[i]; 1519 1520 bcopy(sp->id, &id_key.id, sizeof(id_key.id)); 1521 id_key.creatorid = sp->creatorid; 1522 1523 st = pf_find_state_byid(&id_key); 1524 if (st == NULL) { 1525 V_pfsyncstats.pfsyncs_badstate++; 1526 continue; 1527 } 1528 SET(st->state_flags, PFSTATE_NOSYNC); 1529 pf_unlink_state(st); 1530 } 1531#ifdef __FreeBSD__ 1532 PF_UNLOCK(); 1533#endif 1534 splx(s); 1535 1536 return (len); 1537} 1538 1539int 1540pfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1541{ 1542 struct mbuf *mp; 1543 struct pfsync_del_c *sa, *sp; 1544 struct pf_state_cmp id_key; 1545 struct pf_state *st; 1546 int len = count * sizeof(*sp); 1547 int offp, i; 1548 int s; 1549 1550 mp = m_pulldown(m, offset, len, &offp); 1551 if (mp == NULL) { 1552 V_pfsyncstats.pfsyncs_badlen++; 1553 return (-1); 1554 } 1555 sa = (struct pfsync_del_c *)(mp->m_data + offp); 1556 1557 s = splsoftnet(); 1558#ifdef __FreeBSD__ 1559 PF_LOCK(); 1560#endif 1561 for (i = 0; i < count; i++) { 1562 sp = &sa[i]; 1563 1564 bcopy(&sp->id, &id_key.id, sizeof(id_key.id)); 1565 id_key.creatorid = sp->creatorid; 1566 1567 st = pf_find_state_byid(&id_key); 1568 if (st == NULL) { 1569 V_pfsyncstats.pfsyncs_badstate++; 1570 continue; 1571 } 1572 1573 SET(st->state_flags, PFSTATE_NOSYNC); 1574 pf_unlink_state(st); 1575 } 1576#ifdef __FreeBSD__ 1577 PF_UNLOCK(); 1578#endif 1579 splx(s); 1580 1581 return (len); 1582} 1583 1584int 1585pfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1586{ 1587#ifdef __FreeBSD__ 1588 struct pfsync_softc *sc = V_pfsyncif; 1589#else 1590 struct pfsync_softc *sc = pfsyncif; 1591#endif 1592 struct pfsync_bus *bus; 1593 struct mbuf *mp; 1594 int len = count * sizeof(*bus); 1595 int offp; 1596 1597 /* If we're not waiting for a bulk update, who cares. */ 1598 if (sc->sc_ureq_sent == 0) 1599 return (len); 1600 1601 mp = m_pulldown(m, offset, len, &offp); 1602 if (mp == NULL) { 1603 V_pfsyncstats.pfsyncs_badlen++; 1604 return (-1); 1605 } 1606 bus = (struct pfsync_bus *)(mp->m_data + offp); 1607 1608 switch (bus->status) { 1609 case PFSYNC_BUS_START: 1610#ifdef __FreeBSD__ 1611 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail, 1612 V_pfsyncif); 1613#else 1614 timeout_add_sec(&sc->sc_bulkfail_tmo, 5); /* XXX magic */ 1615#endif 1616#ifdef XXX 1617 pf_pool_limits[PF_LIMIT_STATES].limit / 1618 (PFSYNC_BULKPACKETS * sc->sc_maxcount)); 1619#endif 1620#ifdef __FreeBSD__ 1621 if (V_pf_status.debug >= PF_DEBUG_MISC) 1622#else 1623 if (pf_status.debug >= PF_DEBUG_MISC) 1624#endif 1625 printf("pfsync: received bulk update start\n"); 1626 break; 1627 1628 case PFSYNC_BUS_END: 1629 if (time_uptime - ntohl(bus->endtime) >= 1630 sc->sc_ureq_sent) { 1631 /* that's it, we're happy */ 1632 sc->sc_ureq_sent = 0; 1633 sc->sc_bulk_tries = 0; 1634 timeout_del(&sc->sc_bulkfail_tmo); 1635#if NCARP > 0 1636#ifdef notyet 1637#ifdef __FreeBSD__ 1638 if (!sc->pfsync_sync_ok) 1639#else 1640 if (!pfsync_sync_ok) 1641#endif 1642 carp_group_demote_adj(&sc->sc_if, -1); 1643#endif 1644#endif 1645#ifdef __FreeBSD__ 1646 sc->pfsync_sync_ok = 1; 1647#else 1648 pfsync_sync_ok = 1; 1649#endif 1650#ifdef __FreeBSD__ 1651 if (V_pf_status.debug >= PF_DEBUG_MISC) 1652#else 1653 if (pf_status.debug >= PF_DEBUG_MISC) 1654#endif 1655 printf("pfsync: received valid " 1656 "bulk update end\n"); 1657 } else { 1658#ifdef __FreeBSD__ 1659 if (V_pf_status.debug >= PF_DEBUG_MISC) 1660#else 1661 if (pf_status.debug >= PF_DEBUG_MISC) 1662#endif 1663 printf("pfsync: received invalid " 1664 "bulk update end: bad timestamp\n"); 1665 } 1666 break; 1667 } 1668 1669 return (len); 1670} 1671 1672int 1673pfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1674{ 1675 int len = count * sizeof(struct pfsync_tdb); 1676 1677#if defined(IPSEC) 1678 struct pfsync_tdb *tp; 1679 struct mbuf *mp; 1680 int offp; 1681 int i; 1682 int s; 1683 1684 mp = m_pulldown(m, offset, len, &offp); 1685 if (mp == NULL) { 1686 V_pfsyncstats.pfsyncs_badlen++; 1687 return (-1); 1688 } 1689 tp = (struct pfsync_tdb *)(mp->m_data + offp); 1690 1691 s = splsoftnet(); 1692#ifdef __FreeBSD__ 1693 PF_LOCK(); 1694#endif 1695 for (i = 0; i < count; i++) 1696 pfsync_update_net_tdb(&tp[i]); 1697#ifdef __FreeBSD__ 1698 PF_UNLOCK(); 1699#endif 1700 splx(s); 1701#endif 1702 1703 return (len); 1704} 1705 1706#if defined(IPSEC) 1707/* Update an in-kernel tdb. Silently fail if no tdb is found. */ 1708void 1709pfsync_update_net_tdb(struct pfsync_tdb *pt) 1710{ 1711 struct tdb *tdb; 1712 int s; 1713 1714 /* check for invalid values */ 1715 if (ntohl(pt->spi) <= SPI_RESERVED_MAX || 1716 (pt->dst.sa.sa_family != AF_INET && 1717 pt->dst.sa.sa_family != AF_INET6)) 1718 goto bad; 1719 1720 s = spltdb(); 1721 tdb = gettdb(pt->spi, &pt->dst, pt->sproto); 1722 if (tdb) { 1723 pt->rpl = ntohl(pt->rpl); 1724 pt->cur_bytes = betoh64(pt->cur_bytes); 1725 1726 /* Neither replay nor byte counter should ever decrease. */ 1727 if (pt->rpl < tdb->tdb_rpl || 1728 pt->cur_bytes < tdb->tdb_cur_bytes) { 1729 splx(s); 1730 goto bad; 1731 } 1732 1733 tdb->tdb_rpl = pt->rpl; 1734 tdb->tdb_cur_bytes = pt->cur_bytes; 1735 } 1736 splx(s); 1737 return; 1738 1739bad: 1740#ifdef __FreeBSD__ 1741 if (V_pf_status.debug >= PF_DEBUG_MISC) 1742#else 1743 if (pf_status.debug >= PF_DEBUG_MISC) 1744#endif 1745 printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " 1746 "invalid value\n"); 1747 V_pfsyncstats.pfsyncs_badstate++; 1748 return; 1749} 1750#endif 1751 1752 1753int 1754pfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1755{ 1756 /* check if we are at the right place in the packet */ 1757 if (offset != m->m_pkthdr.len - sizeof(struct pfsync_eof)) 1758 V_pfsyncstats.pfsyncs_badact++; 1759 1760 /* we're done. free and let the caller return */ 1761 m_freem(m); 1762 return (-1); 1763} 1764 1765int 1766pfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1767{ 1768 V_pfsyncstats.pfsyncs_badact++; 1769 1770 m_freem(m); 1771 return (-1); 1772} 1773 1774int 1775pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 1776#ifdef __FreeBSD__ 1777 struct route *rt) 1778#else 1779 struct rtentry *rt) 1780#endif 1781{ 1782 m_freem(m); 1783 return (0); 1784} 1785 1786/* ARGSUSED */ 1787int 1788pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1789{ 1790#ifndef __FreeBSD__ 1791 struct proc *p = curproc; 1792#endif 1793 struct pfsync_softc *sc = ifp->if_softc; 1794 struct ifreq *ifr = (struct ifreq *)data; 1795 struct ip_moptions *imo = &sc->sc_imo; 1796 struct pfsyncreq pfsyncr; 1797 struct ifnet *sifp; 1798 struct ip *ip; 1799 int s, error; 1800 1801 switch (cmd) { 1802#if 0 1803 case SIOCSIFADDR: 1804 case SIOCAIFADDR: 1805 case SIOCSIFDSTADDR: 1806#endif 1807 case SIOCSIFFLAGS: 1808#ifdef __FreeBSD__ 1809 if (ifp->if_flags & IFF_UP) 1810 ifp->if_drv_flags |= IFF_DRV_RUNNING; 1811 else 1812 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1813#else 1814 if (ifp->if_flags & IFF_UP) 1815 ifp->if_flags |= IFF_RUNNING; 1816 else 1817 ifp->if_flags &= ~IFF_RUNNING; 1818#endif 1819 break; 1820 case SIOCSIFMTU: 1821 if (ifr->ifr_mtu <= PFSYNC_MINPKT) 1822 return (EINVAL); 1823 if (ifr->ifr_mtu > MCLBYTES) /* XXX could be bigger */ 1824 ifr->ifr_mtu = MCLBYTES; 1825 if (ifr->ifr_mtu < ifp->if_mtu) { 1826 s = splnet(); 1827#ifdef __FreeBSD__ 1828 PF_LOCK(); 1829#endif 1830 pfsync_sendout(); 1831#ifdef __FreeBSD__ 1832 PF_UNLOCK(); 1833#endif 1834 splx(s); 1835 } 1836 ifp->if_mtu = ifr->ifr_mtu; 1837 break; 1838 case SIOCGETPFSYNC: 1839 bzero(&pfsyncr, sizeof(pfsyncr)); 1840 if (sc->sc_sync_if) { 1841 strlcpy(pfsyncr.pfsyncr_syncdev, 1842 sc->sc_sync_if->if_xname, IFNAMSIZ); 1843 } 1844 pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1845 pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1846 return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))); 1847 1848 case SIOCSETPFSYNC: 1849#ifdef __FreeBSD__ 1850 if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1851#else 1852 if ((error = suser(p, p->p_acflag)) != 0) 1853#endif 1854 return (error); 1855 if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1856 return (error); 1857 1858#ifdef __FreeBSD__ 1859 PF_LOCK(); 1860#endif 1861 if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1862#ifdef __FreeBSD__ 1863 sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 1864#else 1865 sc->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; 1866#endif 1867 else 1868 sc->sc_sync_peer.s_addr = 1869 pfsyncr.pfsyncr_syncpeer.s_addr; 1870 1871 if (pfsyncr.pfsyncr_maxupdates > 255) 1872#ifdef __FreeBSD__ 1873 { 1874 PF_UNLOCK(); 1875#endif 1876 return (EINVAL); 1877#ifdef __FreeBSD__ 1878 } 1879#endif 1880 sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1881 1882 if (pfsyncr.pfsyncr_syncdev[0] == 0) { 1883 sc->sc_sync_if = NULL; 1884#ifdef __FreeBSD__ 1885 PF_UNLOCK(); 1886#endif 1887 if (imo->imo_num_memberships > 0) { 1888 in_delmulti(imo->imo_membership[ 1889 --imo->imo_num_memberships]); 1890 imo->imo_multicast_ifp = NULL; 1891 } 1892 break; 1893 } 1894 1895#ifdef __FreeBSD__ 1896 PF_UNLOCK(); 1897#endif 1898 if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) 1899 return (EINVAL); 1900 1901#ifdef __FreeBSD__ 1902 PF_LOCK(); 1903#endif 1904 s = splnet(); 1905#ifdef __FreeBSD__ 1906 if (sifp->if_mtu < sc->sc_ifp->if_mtu || 1907#else 1908 if (sifp->if_mtu < sc->sc_if.if_mtu || 1909#endif 1910 (sc->sc_sync_if != NULL && 1911 sifp->if_mtu < sc->sc_sync_if->if_mtu) || 1912 sifp->if_mtu < MCLBYTES - sizeof(struct ip)) 1913 pfsync_sendout(); 1914 sc->sc_sync_if = sifp; 1915 1916 if (imo->imo_num_memberships > 0) { 1917#ifdef __FreeBSD__ 1918 PF_UNLOCK(); 1919#endif 1920 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); 1921#ifdef __FreeBSD__ 1922 PF_LOCK(); 1923#endif 1924 imo->imo_multicast_ifp = NULL; 1925 } 1926 1927 if (sc->sc_sync_if && 1928#ifdef __FreeBSD__ 1929 sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1930#else 1931 sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { 1932#endif 1933 struct in_addr addr; 1934 1935 if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { 1936 sc->sc_sync_if = NULL; 1937#ifdef __FreeBSD__ 1938 PF_UNLOCK(); 1939#endif 1940 splx(s); 1941 return (EADDRNOTAVAIL); 1942 } 1943 1944#ifdef __FreeBSD__ 1945 addr.s_addr = htonl(INADDR_PFSYNC_GROUP); 1946#else 1947 addr.s_addr = INADDR_PFSYNC_GROUP; 1948#endif 1949 1950#ifdef __FreeBSD__ 1951 PF_UNLOCK(); 1952#endif 1953 if ((imo->imo_membership[0] = 1954 in_addmulti(&addr, sc->sc_sync_if)) == NULL) { 1955 sc->sc_sync_if = NULL; 1956 splx(s); 1957 return (ENOBUFS); 1958 } 1959#ifdef __FreeBSD__ 1960 PF_LOCK(); 1961#endif 1962 imo->imo_num_memberships++; 1963 imo->imo_multicast_ifp = sc->sc_sync_if; 1964 imo->imo_multicast_ttl = PFSYNC_DFLTTL; 1965 imo->imo_multicast_loop = 0; 1966 } 1967 1968 ip = &sc->sc_template; 1969 bzero(ip, sizeof(*ip)); 1970 ip->ip_v = IPVERSION; 1971 ip->ip_hl = sizeof(sc->sc_template) >> 2; 1972 ip->ip_tos = IPTOS_LOWDELAY; 1973 /* len and id are set later */ 1974#ifdef __FreeBSD__ 1975 ip->ip_off = IP_DF; 1976#else 1977 ip->ip_off = htons(IP_DF); 1978#endif 1979 ip->ip_ttl = PFSYNC_DFLTTL; 1980 ip->ip_p = IPPROTO_PFSYNC; 1981 ip->ip_src.s_addr = INADDR_ANY; 1982 ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr; 1983 1984 if (sc->sc_sync_if) { 1985 /* Request a full state table update. */ 1986 sc->sc_ureq_sent = time_uptime; 1987#if NCARP > 0 1988#ifdef notyet 1989#ifdef __FreeBSD__ 1990 if (sc->pfsync_sync_ok) 1991#else 1992 if (pfsync_sync_ok) 1993#endif 1994 carp_group_demote_adj(&sc->sc_if, 1); 1995#endif 1996#endif 1997#ifdef __FreeBSD__ 1998 sc->pfsync_sync_ok = 0; 1999#else 2000 pfsync_sync_ok = 0; 2001#endif 2002#ifdef __FreeBSD__ 2003 if (V_pf_status.debug >= PF_DEBUG_MISC) 2004#else 2005 if (pf_status.debug >= PF_DEBUG_MISC) 2006#endif 2007 printf("pfsync: requesting bulk update\n"); 2008#ifdef __FreeBSD__ 2009 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 2010 pfsync_bulk_fail, V_pfsyncif); 2011#else 2012 timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 2013#endif 2014 pfsync_request_update(0, 0); 2015 } 2016#ifdef __FreeBSD__ 2017 PF_UNLOCK(); 2018#endif 2019 splx(s); 2020 2021 break; 2022 2023 default: 2024 return (ENOTTY); 2025 } 2026 2027 return (0); 2028} 2029 2030int 2031pfsync_out_state(struct pf_state *st, struct mbuf *m, int offset) 2032{ 2033 struct pfsync_state *sp = (struct pfsync_state *)(m->m_data + offset); 2034 2035 pfsync_state_export(sp, st); 2036 2037 return (sizeof(*sp)); 2038} 2039 2040int 2041pfsync_out_iack(struct pf_state *st, struct mbuf *m, int offset) 2042{ 2043 struct pfsync_ins_ack *iack = 2044 (struct pfsync_ins_ack *)(m->m_data + offset); 2045 2046 iack->id = st->id; 2047 iack->creatorid = st->creatorid; 2048 2049 return (sizeof(*iack)); 2050} 2051 2052int 2053pfsync_out_upd_c(struct pf_state *st, struct mbuf *m, int offset) 2054{ 2055 struct pfsync_upd_c *up = (struct pfsync_upd_c *)(m->m_data + offset); 2056 2057 up->id = st->id; 2058 pf_state_peer_hton(&st->src, &up->src); 2059 pf_state_peer_hton(&st->dst, &up->dst); 2060 up->creatorid = st->creatorid; 2061 2062 up->expire = pf_state_expires(st); 2063 if (up->expire <= time_second) 2064 up->expire = htonl(0); 2065 else 2066 up->expire = htonl(up->expire - time_second); 2067 up->timeout = st->timeout; 2068 2069 bzero(up->_pad, sizeof(up->_pad)); /* XXX */ 2070 2071 return (sizeof(*up)); 2072} 2073 2074int 2075pfsync_out_del(struct pf_state *st, struct mbuf *m, int offset) 2076{ 2077 struct pfsync_del_c *dp = (struct pfsync_del_c *)(m->m_data + offset); 2078 2079 dp->id = st->id; 2080 dp->creatorid = st->creatorid; 2081 2082 SET(st->state_flags, PFSTATE_NOSYNC); 2083 2084 return (sizeof(*dp)); 2085} 2086 2087void 2088pfsync_drop(struct pfsync_softc *sc) 2089{ 2090 struct pf_state *st; 2091 struct pfsync_upd_req_item *ur; 2092#ifdef notyet 2093 struct tdb *t; 2094#endif 2095 int q; 2096 2097 for (q = 0; q < PFSYNC_S_COUNT; q++) { 2098 if (TAILQ_EMPTY(&sc->sc_qs[q])) 2099 continue; 2100 2101 TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2102#ifdef PFSYNC_DEBUG 2103#ifdef __FreeBSD__ 2104 KASSERT(st->sync_state == q, 2105 ("%s: st->sync_state == q", 2106 __FUNCTION__)); 2107#else 2108 KASSERT(st->sync_state == q); 2109#endif 2110#endif 2111 st->sync_state = PFSYNC_S_NONE; 2112 } 2113 TAILQ_INIT(&sc->sc_qs[q]); 2114 } 2115 2116 while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2117 TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2118 pool_put(&sc->sc_pool, ur); 2119 } 2120 2121 sc->sc_plus = NULL; 2122 2123#ifdef notyet 2124 if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2125 TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) 2126 CLR(t->tdb_flags, TDBF_PFSYNC); 2127 2128 TAILQ_INIT(&sc->sc_tdb_q); 2129 } 2130#endif 2131 2132 sc->sc_len = PFSYNC_MINPKT; 2133} 2134 2135void 2136pfsync_sendout(void) 2137{ 2138#ifdef __FreeBSD__ 2139 struct pfsync_softc *sc = V_pfsyncif; 2140#else 2141 struct pfsync_softc *sc = pfsyncif; 2142#endif 2143#if NBPFILTER > 0 2144#ifdef __FreeBSD__ 2145 struct ifnet *ifp = sc->sc_ifp; 2146#else 2147 struct ifnet *ifp = &sc->sc_if; 2148#endif 2149#endif 2150 struct mbuf *m; 2151 struct ip *ip; 2152 struct pfsync_header *ph; 2153 struct pfsync_subheader *subh; 2154 struct pf_state *st; 2155 struct pfsync_upd_req_item *ur; 2156#ifdef notyet 2157 struct tdb *t; 2158#endif 2159#ifdef __FreeBSD__ 2160 size_t pktlen; 2161 int dummy_error; 2162#endif 2163 int offset; 2164 int q, count = 0; 2165 2166#ifdef __FreeBSD__ 2167 PF_LOCK_ASSERT(); 2168#else 2169 splassert(IPL_NET); 2170#endif 2171 2172 if (sc == NULL || sc->sc_len == PFSYNC_MINPKT) 2173 return; 2174 2175#if NBPFILTER > 0 2176 if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) { 2177#else 2178 if (sc->sc_sync_if == NULL) { 2179#endif 2180 pfsync_drop(sc); 2181 return; 2182 } 2183 2184 MGETHDR(m, M_DONTWAIT, MT_DATA); 2185 if (m == NULL) { 2186#ifdef __FreeBSD__ 2187 sc->sc_ifp->if_oerrors++; 2188#else 2189 sc->sc_if.if_oerrors++; 2190#endif 2191 V_pfsyncstats.pfsyncs_onomem++; 2192 pfsync_drop(sc); 2193 return; 2194 } 2195 2196#ifdef __FreeBSD__ 2197 pktlen = max_linkhdr + sc->sc_len; 2198 if (pktlen > MHLEN) { 2199 /* Find the right pool to allocate from. */ 2200 /* XXX: This is ugly. */ 2201 m_cljget(m, M_DONTWAIT, pktlen <= MSIZE ? MSIZE : 2202 pktlen <= MCLBYTES ? MCLBYTES : 2203#if MJUMPAGESIZE != MCLBYTES 2204 pktlen <= MJUMPAGESIZE ? MJUMPAGESIZE : 2205#endif 2206 pktlen <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES); 2207#else 2208 if (max_linkhdr + sc->sc_len > MHLEN) { 2209 MCLGETI(m, M_DONTWAIT, NULL, max_linkhdr + sc->sc_len); 2210#endif 2211 if (!ISSET(m->m_flags, M_EXT)) { 2212 m_free(m); 2213#ifdef __FreeBSD__ 2214 sc->sc_ifp->if_oerrors++; 2215#else 2216 sc->sc_if.if_oerrors++; 2217#endif 2218 V_pfsyncstats.pfsyncs_onomem++; 2219 pfsync_drop(sc); 2220 return; 2221 } 2222 } 2223 m->m_data += max_linkhdr; 2224 m->m_len = m->m_pkthdr.len = sc->sc_len; 2225 2226 /* build the ip header */ 2227 ip = (struct ip *)m->m_data; 2228 bcopy(&sc->sc_template, ip, sizeof(*ip)); 2229 offset = sizeof(*ip); 2230 2231#ifdef __FreeBSD__ 2232 ip->ip_len = m->m_pkthdr.len; 2233#else 2234 ip->ip_len = htons(m->m_pkthdr.len); 2235#endif 2236 ip->ip_id = htons(ip_randomid()); 2237 2238 /* build the pfsync header */ 2239 ph = (struct pfsync_header *)(m->m_data + offset); 2240 bzero(ph, sizeof(*ph)); 2241 offset += sizeof(*ph); 2242 2243 ph->version = PFSYNC_VERSION; 2244 ph->len = htons(sc->sc_len - sizeof(*ip)); 2245#ifdef __FreeBSD__ 2246 bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2247#else 2248 bcopy(pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 2249#endif 2250 2251 /* walk the queues */ 2252 for (q = 0; q < PFSYNC_S_COUNT; q++) { 2253 if (TAILQ_EMPTY(&sc->sc_qs[q])) 2254 continue; 2255 2256 subh = (struct pfsync_subheader *)(m->m_data + offset); 2257 offset += sizeof(*subh); 2258 2259 count = 0; 2260 TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 2261#ifdef PFSYNC_DEBUG 2262#ifdef __FreeBSD__ 2263 KASSERT(st->sync_state == q, 2264 ("%s: st->sync_state == q", 2265 __FUNCTION__)); 2266#else 2267 KASSERT(st->sync_state == q); 2268#endif 2269#endif 2270 2271 offset += pfsync_qs[q].write(st, m, offset); 2272 st->sync_state = PFSYNC_S_NONE; 2273 count++; 2274 } 2275 TAILQ_INIT(&sc->sc_qs[q]); 2276 2277 bzero(subh, sizeof(*subh)); 2278 subh->action = pfsync_qs[q].action; 2279 subh->count = htons(count); 2280 } 2281 2282 if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) { 2283 subh = (struct pfsync_subheader *)(m->m_data + offset); 2284 offset += sizeof(*subh); 2285 2286 count = 0; 2287 while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 2288 TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 2289 2290 bcopy(&ur->ur_msg, m->m_data + offset, 2291 sizeof(ur->ur_msg)); 2292 offset += sizeof(ur->ur_msg); 2293 2294 pool_put(&sc->sc_pool, ur); 2295 2296 count++; 2297 } 2298 2299 bzero(subh, sizeof(*subh)); 2300 subh->action = PFSYNC_ACT_UPD_REQ; 2301 subh->count = htons(count); 2302 } 2303 2304 /* has someone built a custom region for us to add? */ 2305 if (sc->sc_plus != NULL) { 2306 bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen); 2307 offset += sc->sc_pluslen; 2308 2309 sc->sc_plus = NULL; 2310 } 2311 2312#ifdef notyet 2313 if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { 2314 subh = (struct pfsync_subheader *)(m->m_data + offset); 2315 offset += sizeof(*subh); 2316 2317 count = 0; 2318 TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) { 2319 offset += pfsync_out_tdb(t, m, offset); 2320 CLR(t->tdb_flags, TDBF_PFSYNC); 2321 2322 count++; 2323 } 2324 TAILQ_INIT(&sc->sc_tdb_q); 2325 2326 bzero(subh, sizeof(*subh)); 2327 subh->action = PFSYNC_ACT_TDB; 2328 subh->count = htons(count); 2329 } 2330#endif 2331 2332 subh = (struct pfsync_subheader *)(m->m_data + offset); 2333 offset += sizeof(*subh); 2334 2335 bzero(subh, sizeof(*subh)); 2336 subh->action = PFSYNC_ACT_EOF; 2337 subh->count = htons(1); 2338 2339 /* XXX write checksum in EOF here */ 2340 2341 /* we're done, let's put it on the wire */ 2342#if NBPFILTER > 0 2343 if (ifp->if_bpf) { 2344 m->m_data += sizeof(*ip); 2345 m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip); 2346#ifdef __FreeBSD__ 2347 BPF_MTAP(ifp, m); 2348#else 2349 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 2350#endif 2351 m->m_data -= sizeof(*ip); 2352 m->m_len = m->m_pkthdr.len = sc->sc_len; 2353 } 2354 2355 if (sc->sc_sync_if == NULL) { 2356 sc->sc_len = PFSYNC_MINPKT; 2357 m_freem(m); 2358 return; 2359 } 2360#endif 2361 2362#ifdef __FreeBSD__ 2363 sc->sc_ifp->if_opackets++; 2364 sc->sc_ifp->if_obytes += m->m_pkthdr.len; 2365 sc->sc_len = PFSYNC_MINPKT; 2366 2367 IFQ_ENQUEUE(&sc->sc_ifp->if_snd, m, dummy_error); 2368 schednetisr(NETISR_PFSYNC); 2369#else 2370 sc->sc_if.if_opackets++; 2371 sc->sc_if.if_obytes += m->m_pkthdr.len; 2372 2373 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0) 2374 pfsyncstats.pfsyncs_opackets++; 2375 else 2376 pfsyncstats.pfsyncs_oerrors++; 2377 2378 /* start again */ 2379 sc->sc_len = PFSYNC_MINPKT; 2380#endif 2381} 2382 2383void 2384pfsync_insert_state(struct pf_state *st) 2385{ 2386#ifdef __FreeBSD__ 2387 struct pfsync_softc *sc = V_pfsyncif; 2388#else 2389 struct pfsync_softc *sc = pfsyncif; 2390#endif 2391 2392#ifdef __FreeBSD__ 2393 PF_LOCK_ASSERT(); 2394#else 2395 splassert(IPL_SOFTNET); 2396#endif 2397 2398 if (ISSET(st->rule.ptr->rule_flag, PFRULE_NOSYNC) || 2399 st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) { 2400 SET(st->state_flags, PFSTATE_NOSYNC); 2401 return; 2402 } 2403 2404 if (sc == NULL || ISSET(st->state_flags, PFSTATE_NOSYNC)) 2405 return; 2406 2407#ifdef PFSYNC_DEBUG 2408#ifdef __FreeBSD__ 2409 KASSERT(st->sync_state == PFSYNC_S_NONE, 2410 ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2411#else 2412 KASSERT(st->sync_state == PFSYNC_S_NONE); 2413#endif 2414#endif 2415 2416 if (sc->sc_len == PFSYNC_MINPKT) 2417#ifdef __FreeBSD__ 2418 callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2419 V_pfsyncif); 2420#else 2421 timeout_add_sec(&sc->sc_tmo, 1); 2422#endif 2423 2424 pfsync_q_ins(st, PFSYNC_S_INS); 2425 2426 if (ISSET(st->state_flags, PFSTATE_ACK)) 2427#ifdef __FreeBSD__ 2428 pfsync_sendout(); 2429#else 2430 schednetisr(NETISR_PFSYNC); 2431#endif 2432 else 2433 st->sync_updates = 0; 2434} 2435 2436int defer = 10; 2437 2438int 2439pfsync_defer(struct pf_state *st, struct mbuf *m) 2440{ 2441#ifdef __FreeBSD__ 2442 struct pfsync_softc *sc = V_pfsyncif; 2443#else 2444 struct pfsync_softc *sc = pfsyncif; 2445#endif 2446 struct pfsync_deferral *pd; 2447 2448#ifdef __FreeBSD__ 2449 PF_LOCK_ASSERT(); 2450#else 2451 splassert(IPL_SOFTNET); 2452#endif 2453 2454 if (sc->sc_deferred >= 128) 2455 pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 2456 2457 pd = pool_get(&sc->sc_pool, M_NOWAIT); 2458 if (pd == NULL) 2459 return (0); 2460 sc->sc_deferred++; 2461 2462#ifdef __FreeBSD__ 2463 m->m_flags |= M_SKIP_FIREWALL; 2464#else 2465 m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; 2466#endif 2467 SET(st->state_flags, PFSTATE_ACK); 2468 2469 pd->pd_st = st; 2470 pd->pd_m = m; 2471 2472 TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry); 2473#ifdef __FreeBSD__ 2474 callout_init(&pd->pd_tmo, CALLOUT_MPSAFE); 2475 callout_reset(&pd->pd_tmo, defer, pfsync_defer_tmo, 2476 pd); 2477#else 2478 timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd); 2479 timeout_add(&pd->pd_tmo, defer); 2480#endif 2481 2482 return (1); 2483} 2484 2485void 2486pfsync_undefer(struct pfsync_deferral *pd, int drop) 2487{ 2488#ifdef __FreeBSD__ 2489 struct pfsync_softc *sc = V_pfsyncif; 2490#else 2491 struct pfsync_softc *sc = pfsyncif; 2492#endif 2493 int s; 2494 2495#ifdef __FreeBSD__ 2496 PF_LOCK_ASSERT(); 2497#else 2498 splassert(IPL_SOFTNET); 2499#endif 2500 2501 TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 2502 sc->sc_deferred--; 2503 2504 CLR(pd->pd_st->state_flags, PFSTATE_ACK); 2505 timeout_del(&pd->pd_tmo); /* bah */ 2506 if (drop) 2507 m_freem(pd->pd_m); 2508 else { 2509 s = splnet(); 2510#ifdef __FreeBSD__ 2511 /* XXX: use pf_defered?! */ 2512 PF_UNLOCK(); 2513#endif 2514 ip_output(pd->pd_m, (void *)NULL, (void *)NULL, 0, 2515 (void *)NULL, (void *)NULL); 2516#ifdef __FreeBSD__ 2517 PF_LOCK(); 2518#endif 2519 splx(s); 2520 } 2521 2522 pool_put(&sc->sc_pool, pd); 2523} 2524 2525void 2526pfsync_defer_tmo(void *arg) 2527{ 2528#if defined(__FreeBSD__) && defined(VIMAGE) 2529 struct pfsync_deferral *pd = arg; 2530#endif 2531 int s; 2532 2533 s = splsoftnet(); 2534#ifdef __FreeBSD__ 2535 CURVNET_SET(pd->pd_m->m_pkthdr.rcvif->if_vnet); /* XXX */ 2536 PF_LOCK(); 2537#endif 2538 pfsync_undefer(arg, 0); 2539#ifdef __FreeBSD__ 2540 PF_UNLOCK(); 2541 CURVNET_RESTORE(); 2542#endif 2543 splx(s); 2544} 2545 2546void 2547pfsync_deferred(struct pf_state *st, int drop) 2548{ 2549#ifdef __FreeBSD__ 2550 struct pfsync_softc *sc = V_pfsyncif; 2551#else 2552 struct pfsync_softc *sc = pfsyncif; 2553#endif 2554 struct pfsync_deferral *pd; 2555 2556 TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) { 2557 if (pd->pd_st == st) { 2558 pfsync_undefer(pd, drop); 2559 return; 2560 } 2561 } 2562 2563 panic("pfsync_send_deferred: unable to find deferred state"); 2564} 2565 2566u_int pfsync_upds = 0; 2567 2568void 2569pfsync_update_state(struct pf_state *st) 2570{ 2571#ifdef __FreeBSD__ 2572 struct pfsync_softc *sc = V_pfsyncif; 2573#else 2574 struct pfsync_softc *sc = pfsyncif; 2575#endif 2576 int sync = 0; 2577 2578#ifdef __FreeBSD__ 2579 PF_LOCK_ASSERT(); 2580#else 2581 splassert(IPL_SOFTNET); 2582#endif 2583 2584 if (sc == NULL) 2585 return; 2586 2587 if (ISSET(st->state_flags, PFSTATE_ACK)) 2588 pfsync_deferred(st, 0); 2589 if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2590 if (st->sync_state != PFSYNC_S_NONE) 2591 pfsync_q_del(st); 2592 return; 2593 } 2594 2595 if (sc->sc_len == PFSYNC_MINPKT) 2596#ifdef __FreeBSD__ 2597 callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2598 V_pfsyncif); 2599#else 2600 timeout_add_sec(&sc->sc_tmo, 1); 2601#endif 2602 2603 switch (st->sync_state) { 2604 case PFSYNC_S_UPD_C: 2605 case PFSYNC_S_UPD: 2606 case PFSYNC_S_INS: 2607 /* we're already handling it */ 2608 2609 st->sync_updates++; 2610 if (st->sync_updates >= sc->sc_maxupdates) 2611 sync = 1; 2612 break; 2613 2614 case PFSYNC_S_IACK: 2615 pfsync_q_del(st); 2616 case PFSYNC_S_NONE: 2617 pfsync_q_ins(st, PFSYNC_S_UPD_C); 2618 st->sync_updates = 0; 2619 break; 2620 2621 default: 2622 panic("pfsync_update_state: unexpected sync state %d", 2623 st->sync_state); 2624 } 2625 2626 if (sync || (time_second - st->pfsync_time) < 2) { 2627 pfsync_upds++; 2628#ifdef __FreeBSD__ 2629 pfsync_sendout(); 2630#else 2631 schednetisr(NETISR_PFSYNC); 2632#endif 2633 } 2634} 2635 2636void 2637pfsync_request_update(u_int32_t creatorid, u_int64_t id) 2638{ 2639#ifdef __FreeBSD__ 2640 struct pfsync_softc *sc = V_pfsyncif; 2641#else 2642 struct pfsync_softc *sc = pfsyncif; 2643#endif 2644 struct pfsync_upd_req_item *item; 2645 size_t nlen = sizeof(struct pfsync_upd_req); 2646 int s; 2647 2648 PF_LOCK_ASSERT(); 2649 2650 /* 2651 * this code does nothing to prevent multiple update requests for the 2652 * same state being generated. 2653 */ 2654 2655 item = pool_get(&sc->sc_pool, PR_NOWAIT); 2656 if (item == NULL) { 2657 /* XXX stats */ 2658 return; 2659 } 2660 2661 item->ur_msg.id = id; 2662 item->ur_msg.creatorid = creatorid; 2663 2664 if (TAILQ_EMPTY(&sc->sc_upd_req_list)) 2665 nlen += sizeof(struct pfsync_subheader); 2666 2667#ifdef __FreeBSD__ 2668 if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2669#else 2670 if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2671#endif 2672 s = splnet(); 2673 pfsync_sendout(); 2674 splx(s); 2675 2676 nlen = sizeof(struct pfsync_subheader) + 2677 sizeof(struct pfsync_upd_req); 2678 } 2679 2680 TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry); 2681 sc->sc_len += nlen; 2682 2683#ifdef __FreeBSD__ 2684 pfsync_sendout(); 2685#else 2686 schednetisr(NETISR_PFSYNC); 2687#endif 2688} 2689 2690void 2691pfsync_update_state_req(struct pf_state *st) 2692{ 2693#ifdef __FreeBSD__ 2694 struct pfsync_softc *sc = V_pfsyncif; 2695#else 2696 struct pfsync_softc *sc = pfsyncif; 2697#endif 2698 2699 PF_LOCK_ASSERT(); 2700 2701 if (sc == NULL) 2702 panic("pfsync_update_state_req: nonexistant instance"); 2703 2704 if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2705 if (st->sync_state != PFSYNC_S_NONE) 2706 pfsync_q_del(st); 2707 return; 2708 } 2709 2710 switch (st->sync_state) { 2711 case PFSYNC_S_UPD_C: 2712 case PFSYNC_S_IACK: 2713 pfsync_q_del(st); 2714 case PFSYNC_S_NONE: 2715 pfsync_q_ins(st, PFSYNC_S_UPD); 2716#ifdef __FreeBSD__ 2717 pfsync_sendout(); 2718#else 2719 schednetisr(NETISR_PFSYNC); 2720#endif 2721 return; 2722 2723 case PFSYNC_S_INS: 2724 case PFSYNC_S_UPD: 2725 case PFSYNC_S_DEL: 2726 /* we're already handling it */ 2727 return; 2728 2729 default: 2730 panic("pfsync_update_state_req: unexpected sync state %d", 2731 st->sync_state); 2732 } 2733} 2734 2735void 2736pfsync_delete_state(struct pf_state *st) 2737{ 2738#ifdef __FreeBSD__ 2739 struct pfsync_softc *sc = V_pfsyncif; 2740#else 2741 struct pfsync_softc *sc = pfsyncif; 2742#endif 2743 2744#ifdef __FreeBSD__ 2745 PF_LOCK_ASSERT(); 2746#else 2747 splassert(IPL_SOFTNET); 2748#endif 2749 2750 if (sc == NULL) 2751 return; 2752 2753 if (ISSET(st->state_flags, PFSTATE_ACK)) 2754 pfsync_deferred(st, 1); 2755 if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { 2756 if (st->sync_state != PFSYNC_S_NONE) 2757 pfsync_q_del(st); 2758 return; 2759 } 2760 2761 if (sc->sc_len == PFSYNC_MINPKT) 2762#ifdef __FreeBSD__ 2763 callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, 2764 V_pfsyncif); 2765#else 2766 timeout_add_sec(&sc->sc_tmo, 1); 2767#endif 2768 2769 switch (st->sync_state) { 2770 case PFSYNC_S_INS: 2771 /* we never got to tell the world so just forget about it */ 2772 pfsync_q_del(st); 2773 return; 2774 2775 case PFSYNC_S_UPD_C: 2776 case PFSYNC_S_UPD: 2777 case PFSYNC_S_IACK: 2778 pfsync_q_del(st); 2779 /* FALLTHROUGH to putting it on the del list */ 2780 2781 case PFSYNC_S_NONE: 2782 pfsync_q_ins(st, PFSYNC_S_DEL); 2783 return; 2784 2785 default: 2786 panic("pfsync_delete_state: unexpected sync state %d", 2787 st->sync_state); 2788 } 2789} 2790 2791void 2792pfsync_clear_states(u_int32_t creatorid, const char *ifname) 2793{ 2794 struct { 2795 struct pfsync_subheader subh; 2796 struct pfsync_clr clr; 2797 } __packed r; 2798 2799#ifdef __FreeBSD__ 2800 struct pfsync_softc *sc = V_pfsyncif; 2801#else 2802 struct pfsync_softc *sc = pfsyncif; 2803#endif 2804 2805#ifdef __FreeBSD__ 2806 PF_LOCK_ASSERT(); 2807#else 2808 splassert(IPL_SOFTNET); 2809#endif 2810 2811 if (sc == NULL) 2812 return; 2813 2814 bzero(&r, sizeof(r)); 2815 2816 r.subh.action = PFSYNC_ACT_CLR; 2817 r.subh.count = htons(1); 2818 2819 strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname)); 2820 r.clr.creatorid = creatorid; 2821 2822 pfsync_send_plus(&r, sizeof(r)); 2823} 2824 2825void 2826pfsync_q_ins(struct pf_state *st, int q) 2827{ 2828#ifdef __FreeBSD__ 2829 struct pfsync_softc *sc = V_pfsyncif; 2830#else 2831 struct pfsync_softc *sc = pfsyncif; 2832#endif 2833 size_t nlen = pfsync_qs[q].len; 2834 int s; 2835 2836 PF_LOCK_ASSERT(); 2837 2838#ifdef __FreeBSD__ 2839 KASSERT(st->sync_state == PFSYNC_S_NONE, 2840 ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); 2841#else 2842 KASSERT(st->sync_state == PFSYNC_S_NONE); 2843#endif 2844 2845#if 1 || defined(PFSYNC_DEBUG) 2846 if (sc->sc_len < PFSYNC_MINPKT) 2847#ifdef __FreeBSD__ 2848 panic("pfsync pkt len is too low %zu", sc->sc_len); 2849#else 2850 panic("pfsync pkt len is too low %d", sc->sc_len); 2851#endif 2852#endif 2853 if (TAILQ_EMPTY(&sc->sc_qs[q])) 2854 nlen += sizeof(struct pfsync_subheader); 2855 2856#ifdef __FreeBSD__ 2857 if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 2858#else 2859 if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2860#endif 2861 s = splnet(); 2862 pfsync_sendout(); 2863 splx(s); 2864 2865 nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len; 2866 } 2867 2868 sc->sc_len += nlen; 2869 TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list); 2870 st->sync_state = q; 2871} 2872 2873void 2874pfsync_q_del(struct pf_state *st) 2875{ 2876#ifdef __FreeBSD__ 2877 struct pfsync_softc *sc = V_pfsyncif; 2878#else 2879 struct pfsync_softc *sc = pfsyncif; 2880#endif 2881 int q = st->sync_state; 2882 2883#ifdef __FreeBSD__ 2884 KASSERT(st->sync_state != PFSYNC_S_NONE, 2885 ("%s: st->sync_state != PFSYNC_S_NONE", __FUNCTION__)); 2886#else 2887 KASSERT(st->sync_state != PFSYNC_S_NONE); 2888#endif 2889 2890 sc->sc_len -= pfsync_qs[q].len; 2891 TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list); 2892 st->sync_state = PFSYNC_S_NONE; 2893 2894 if (TAILQ_EMPTY(&sc->sc_qs[q])) 2895 sc->sc_len -= sizeof(struct pfsync_subheader); 2896} 2897 2898#ifdef notyet 2899void 2900pfsync_update_tdb(struct tdb *t, int output) 2901{ 2902#ifdef __FreeBSD__ 2903 struct pfsync_softc *sc = V_pfsyncif; 2904#else 2905 struct pfsync_softc *sc = pfsyncif; 2906#endif 2907 size_t nlen = sizeof(struct pfsync_tdb); 2908 int s; 2909 2910 if (sc == NULL) 2911 return; 2912 2913 if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) { 2914 if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2915 nlen += sizeof(struct pfsync_subheader); 2916 2917 if (sc->sc_len + nlen > sc->sc_if.if_mtu) { 2918 s = splnet(); 2919 PF_LOCK(); 2920 pfsync_sendout(); 2921 PF_UNLOCK(); 2922 splx(s); 2923 2924 nlen = sizeof(struct pfsync_subheader) + 2925 sizeof(struct pfsync_tdb); 2926 } 2927 2928 sc->sc_len += nlen; 2929 TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry); 2930 SET(t->tdb_flags, TDBF_PFSYNC); 2931 t->tdb_updates = 0; 2932 } else { 2933 if (++t->tdb_updates >= sc->sc_maxupdates) 2934 schednetisr(NETISR_PFSYNC); 2935 } 2936 2937 if (output) 2938 SET(t->tdb_flags, TDBF_PFSYNC_RPL); 2939 else 2940 CLR(t->tdb_flags, TDBF_PFSYNC_RPL); 2941} 2942 2943void 2944pfsync_delete_tdb(struct tdb *t) 2945{ 2946#ifdef __FreeBSD__ 2947 struct pfsync_softc *sc = V_pfsyncif; 2948#else 2949 struct pfsync_softc *sc = pfsyncif; 2950#endif 2951 2952 if (sc == NULL || !ISSET(t->tdb_flags, TDBF_PFSYNC)) 2953 return; 2954 2955 sc->sc_len -= sizeof(struct pfsync_tdb); 2956 TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry); 2957 CLR(t->tdb_flags, TDBF_PFSYNC); 2958 2959 if (TAILQ_EMPTY(&sc->sc_tdb_q)) 2960 sc->sc_len -= sizeof(struct pfsync_subheader); 2961} 2962 2963int 2964pfsync_out_tdb(struct tdb *t, struct mbuf *m, int offset) 2965{ 2966 struct pfsync_tdb *ut = (struct pfsync_tdb *)(m->m_data + offset); 2967 2968 bzero(ut, sizeof(*ut)); 2969 ut->spi = t->tdb_spi; 2970 bcopy(&t->tdb_dst, &ut->dst, sizeof(ut->dst)); 2971 /* 2972 * When a failover happens, the master's rpl is probably above 2973 * what we see here (we may be up to a second late), so 2974 * increase it a bit for outbound tdbs to manage most such 2975 * situations. 2976 * 2977 * For now, just add an offset that is likely to be larger 2978 * than the number of packets we can see in one second. The RFC 2979 * just says the next packet must have a higher seq value. 2980 * 2981 * XXX What is a good algorithm for this? We could use 2982 * a rate-determined increase, but to know it, we would have 2983 * to extend struct tdb. 2984 * XXX pt->rpl can wrap over MAXINT, but if so the real tdb 2985 * will soon be replaced anyway. For now, just don't handle 2986 * this edge case. 2987 */ 2988#define RPL_INCR 16384 2989 ut->rpl = htonl(t->tdb_rpl + (ISSET(t->tdb_flags, TDBF_PFSYNC_RPL) ? 2990 RPL_INCR : 0)); 2991 ut->cur_bytes = htobe64(t->tdb_cur_bytes); 2992 ut->sproto = t->tdb_sproto; 2993 2994 return (sizeof(*ut)); 2995} 2996#endif 2997 2998void 2999pfsync_bulk_start(void) 3000{ 3001#ifdef __FreeBSD__ 3002 struct pfsync_softc *sc = V_pfsyncif; 3003#else 3004 struct pfsync_softc *sc = pfsyncif; 3005#endif 3006 3007#ifdef __FreeBSD__ 3008 if (V_pf_status.debug >= PF_DEBUG_MISC) 3009#else 3010 if (pf_status.debug >= PF_DEBUG_MISC) 3011#endif 3012 printf("pfsync: received bulk update request\n"); 3013 3014#ifdef __FreeBSD__ 3015 PF_LOCK(); 3016 if (TAILQ_EMPTY(&V_state_list)) 3017#else 3018 if (TAILQ_EMPTY(&state_list)) 3019#endif 3020 pfsync_bulk_status(PFSYNC_BUS_END); 3021 else { 3022 sc->sc_ureq_received = time_uptime; 3023 if (sc->sc_bulk_next == NULL) 3024#ifdef __FreeBSD__ 3025 sc->sc_bulk_next = TAILQ_FIRST(&V_state_list); 3026#else 3027 sc->sc_bulk_next = TAILQ_FIRST(&state_list); 3028#endif 3029 sc->sc_bulk_last = sc->sc_bulk_next; 3030 3031 pfsync_bulk_status(PFSYNC_BUS_START); 3032 callout_reset(&sc->sc_bulk_tmo, 1, 3033 pfsync_bulk_update, sc); 3034 } 3035#ifdef __FreeBSD__ 3036 PF_UNLOCK(); 3037#endif 3038} 3039 3040void 3041pfsync_bulk_update(void *arg) 3042{ 3043 struct pfsync_softc *sc = arg; 3044 struct pf_state *st = sc->sc_bulk_next; 3045 int i = 0; 3046 int s; 3047 3048 PF_LOCK_ASSERT(); 3049 3050 s = splsoftnet(); 3051#ifdef __FreeBSD__ 3052 CURVNET_SET(sc->sc_ifp->if_vnet); 3053#endif 3054 for (;;) { 3055 if (st->sync_state == PFSYNC_S_NONE && 3056 st->timeout < PFTM_MAX && 3057 st->pfsync_time <= sc->sc_ureq_received) { 3058 pfsync_update_state_req(st); 3059 i++; 3060 } 3061 3062 st = TAILQ_NEXT(st, entry_list); 3063 if (st == NULL) 3064#ifdef __FreeBSD__ 3065 st = TAILQ_FIRST(&V_state_list); 3066#else 3067 st = TAILQ_FIRST(&state_list); 3068#endif 3069 3070 if (st == sc->sc_bulk_last) { 3071 /* we're done */ 3072 sc->sc_bulk_next = NULL; 3073 sc->sc_bulk_last = NULL; 3074 pfsync_bulk_status(PFSYNC_BUS_END); 3075 break; 3076 } 3077 3078#ifdef __FreeBSD__ 3079 if (i > 1 && (sc->sc_ifp->if_mtu - sc->sc_len) < 3080#else 3081 if (i > 1 && (sc->sc_if.if_mtu - sc->sc_len) < 3082#endif 3083 sizeof(struct pfsync_state)) { 3084 /* we've filled a packet */ 3085 sc->sc_bulk_next = st; 3086#ifdef __FreeBSD__ 3087 callout_reset(&sc->sc_bulk_tmo, 1, 3088 pfsync_bulk_update, sc); 3089#else 3090 timeout_add(&sc->sc_bulk_tmo, 1); 3091#endif 3092 break; 3093 } 3094 } 3095 3096#ifdef __FreeBSD__ 3097 CURVNET_RESTORE(); 3098#endif 3099 splx(s); 3100} 3101 3102void 3103pfsync_bulk_status(u_int8_t status) 3104{ 3105 struct { 3106 struct pfsync_subheader subh; 3107 struct pfsync_bus bus; 3108 } __packed r; 3109 3110#ifdef __FreeBSD__ 3111 struct pfsync_softc *sc = V_pfsyncif; 3112#else 3113 struct pfsync_softc *sc = pfsyncif; 3114#endif 3115 3116 PF_LOCK_ASSERT(); 3117 3118 bzero(&r, sizeof(r)); 3119 3120 r.subh.action = PFSYNC_ACT_BUS; 3121 r.subh.count = htons(1); 3122 3123#ifdef __FreeBSD__ 3124 r.bus.creatorid = V_pf_status.hostid; 3125#else 3126 r.bus.creatorid = pf_status.hostid; 3127#endif 3128 r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received); 3129 r.bus.status = status; 3130 3131 pfsync_send_plus(&r, sizeof(r)); 3132} 3133 3134void 3135pfsync_bulk_fail(void *arg) 3136{ 3137 struct pfsync_softc *sc = arg; 3138 3139#ifdef __FreeBSD__ 3140 CURVNET_SET(sc->sc_ifp->if_vnet); 3141#endif 3142 3143 if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 3144 /* Try again */ 3145#ifdef __FreeBSD__ 3146 callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 3147 pfsync_bulk_fail, V_pfsyncif); 3148#else 3149 timeout_add_sec(&sc->sc_bulkfail_tmo, 5); 3150#endif 3151 PF_LOCK(); 3152 pfsync_request_update(0, 0); 3153 PF_UNLOCK(); 3154 } else { 3155 /* Pretend like the transfer was ok */ 3156 sc->sc_ureq_sent = 0; 3157 sc->sc_bulk_tries = 0; 3158#if NCARP > 0 3159#ifdef notyet 3160#ifdef __FreeBSD__ 3161 if (!sc->pfsync_sync_ok) 3162#else 3163 if (!pfsync_sync_ok) 3164#endif 3165 carp_group_demote_adj(&sc->sc_if, -1); 3166#endif 3167#endif 3168#ifdef __FreeBSD__ 3169 sc->pfsync_sync_ok = 1; 3170#else 3171 pfsync_sync_ok = 1; 3172#endif 3173#ifdef __FreeBSD__ 3174 if (V_pf_status.debug >= PF_DEBUG_MISC) 3175#else 3176 if (pf_status.debug >= PF_DEBUG_MISC) 3177#endif 3178 printf("pfsync: failed to receive bulk update\n"); 3179 } 3180 3181#ifdef __FreeBSD__ 3182 CURVNET_RESTORE(); 3183#endif 3184} 3185 3186void 3187pfsync_send_plus(void *plus, size_t pluslen) 3188{ 3189#ifdef __FreeBSD__ 3190 struct pfsync_softc *sc = V_pfsyncif; 3191#else 3192 struct pfsync_softc *sc = pfsyncif; 3193#endif 3194 int s; 3195 3196 PF_LOCK_ASSERT(); 3197 3198#ifdef __FreeBSD__ 3199 if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) { 3200#else 3201 if (sc->sc_len + pluslen > sc->sc_if.if_mtu) { 3202#endif 3203 s = splnet(); 3204 pfsync_sendout(); 3205 splx(s); 3206 } 3207 3208 sc->sc_plus = plus; 3209 sc->sc_len += (sc->sc_pluslen = pluslen); 3210 3211 s = splnet(); 3212 pfsync_sendout(); 3213 splx(s); 3214} 3215 3216int 3217pfsync_up(void) 3218{ 3219#ifdef __FreeBSD__ 3220 struct pfsync_softc *sc = V_pfsyncif; 3221#else 3222 struct pfsync_softc *sc = pfsyncif; 3223#endif 3224 3225#ifdef __FreeBSD__ 3226 if (sc == NULL || !ISSET(sc->sc_ifp->if_flags, IFF_DRV_RUNNING)) 3227#else 3228 if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING)) 3229#endif 3230 return (0); 3231 3232 return (1); 3233} 3234 3235int 3236pfsync_state_in_use(struct pf_state *st) 3237{ 3238#ifdef __FreeBSD__ 3239 struct pfsync_softc *sc = V_pfsyncif; 3240#else 3241 struct pfsync_softc *sc = pfsyncif; 3242#endif 3243 3244 if (sc == NULL) 3245 return (0); 3246 3247 if (st->sync_state != PFSYNC_S_NONE || 3248 st == sc->sc_bulk_next || 3249 st == sc->sc_bulk_last) 3250 return (1); 3251 3252 return (0); 3253} 3254 3255u_int pfsync_ints; 3256u_int pfsync_tmos; 3257 3258void 3259pfsync_timeout(void *arg) 3260{ 3261#if defined(__FreeBSD__) && defined(VIMAGE) 3262 struct pfsync_softc *sc = arg; 3263#endif 3264 int s; 3265 3266#ifdef __FreeBSD__ 3267 CURVNET_SET(sc->sc_ifp->if_vnet); 3268#endif 3269 3270 pfsync_tmos++; 3271 3272 s = splnet(); 3273#ifdef __FreeBSD__ 3274 PF_LOCK(); 3275#endif 3276 pfsync_sendout(); 3277#ifdef __FreeBSD__ 3278 PF_UNLOCK(); 3279#endif 3280 splx(s); 3281 3282#ifdef __FreeBSD__ 3283 CURVNET_RESTORE(); 3284#endif 3285} 3286 3287/* this is a softnet/netisr handler */ 3288void 3289#ifdef __FreeBSD__ 3290pfsyncintr(void *arg) 3291{ 3292 struct pfsync_softc *sc = arg; 3293 struct mbuf *m; 3294 3295 CURVNET_SET(sc->sc_ifp->if_vnet); 3296 pfsync_ints++; 3297 3298 for (;;) { 3299 IF_DEQUEUE(&sc->sc_ifp->if_snd, m); 3300 if (m == 0) 3301 break; 3302 3303 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) 3304 == 0) 3305 V_pfsyncstats.pfsyncs_opackets++; 3306 else 3307 V_pfsyncstats.pfsyncs_oerrors++; 3308 } 3309 CURVNET_RESTORE(); 3310} 3311#else 3312pfsyncintr(void) 3313{ 3314 int s; 3315 3316 pfsync_ints++; 3317 3318 s = splnet(); 3319 pfsync_sendout(); 3320 splx(s); 3321} 3322#endif 3323 3324int 3325pfsync_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 3326 size_t newlen) 3327{ 3328 3329#ifdef notyet 3330 /* All sysctl names at this level are terminal. */ 3331 if (namelen != 1) 3332 return (ENOTDIR); 3333 3334 switch (name[0]) { 3335 case PFSYNCCTL_STATS: 3336 if (newp != NULL) 3337 return (EPERM); 3338 return (sysctl_struct(oldp, oldlenp, newp, newlen, 3339 &V_pfsyncstats, sizeof(V_pfsyncstats))); 3340 } 3341#endif 3342 return (ENOPROTOOPT); 3343} 3344 3345#ifdef __FreeBSD__ 3346void 3347pfsync_ifdetach(void *arg, struct ifnet *ifp) 3348{ 3349 struct pfsync_softc *sc = (struct pfsync_softc *)arg; 3350 struct ip_moptions *imo; 3351 3352 if (sc == NULL || sc->sc_sync_if != ifp) 3353 return; /* not for us; unlocked read */ 3354 3355 CURVNET_SET(sc->sc_ifp->if_vnet); 3356 3357 PF_LOCK(); 3358 3359 /* Deal with a member interface going away from under us. */ 3360 sc->sc_sync_if = NULL; 3361 imo = &sc->sc_imo; 3362 if (imo->imo_num_memberships > 0) { 3363 KASSERT(imo->imo_num_memberships == 1, 3364 ("%s: imo_num_memberships != 1", __func__)); 3365 /* 3366 * Our event handler is always called after protocol 3367 * domains have been detached from the underlying ifnet. 3368 * Do not call in_delmulti(); we held a single reference 3369 * which the protocol domain has purged in in_purgemaddrs(). 3370 */ 3371 PF_UNLOCK(); 3372 imo->imo_membership[--imo->imo_num_memberships] = NULL; 3373 PF_LOCK(); 3374 imo->imo_multicast_ifp = NULL; 3375 } 3376 3377 PF_UNLOCK(); 3378 3379 CURVNET_RESTORE(); 3380} 3381 3382static int 3383vnet_pfsync_init(const void *unused) 3384{ 3385 int error = 0; 3386 3387 pfsyncattach(0); 3388 3389 error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif, 3390 SWI_NET, INTR_MPSAFE, &pfsync_swi.pfsync_swi_cookie); 3391 if (error) 3392 panic("%s: swi_add %d", __func__, error); 3393 3394 pfsync_state_import_ptr = pfsync_state_import; 3395 pfsync_up_ptr = pfsync_up; 3396 pfsync_insert_state_ptr = pfsync_insert_state; 3397 pfsync_update_state_ptr = pfsync_update_state; 3398 pfsync_delete_state_ptr = pfsync_delete_state; 3399 pfsync_clear_states_ptr = pfsync_clear_states; 3400 pfsync_state_in_use_ptr = pfsync_state_in_use; 3401 pfsync_defer_ptr = pfsync_defer; 3402 3403 return (0); 3404} 3405 3406static int 3407vnet_pfsync_uninit(const void *unused) 3408{ 3409 3410 swi_remove(pfsync_swi.pfsync_swi_cookie); 3411 3412 pfsync_state_import_ptr = NULL; 3413 pfsync_up_ptr = NULL; 3414 pfsync_insert_state_ptr = NULL; 3415 pfsync_update_state_ptr = NULL; 3416 pfsync_delete_state_ptr = NULL; 3417 pfsync_clear_states_ptr = NULL; 3418 pfsync_state_in_use_ptr = NULL; 3419 pfsync_defer_ptr = NULL; 3420 3421 if_clone_detach(&pfsync_cloner); 3422 3423 return (0); 3424} 3425 3426/* Define startup order. */ 3427#define PFSYNC_SYSINIT_ORDER SI_SUB_PROTO_IF 3428#define PFSYNC_MODEVENT_ORDER (SI_ORDER_FIRST) /* On boot slot in here. */ 3429#define PFSYNC_VNET_ORDER (PFSYNC_MODEVENT_ORDER + 2) /* Later still. */ 3430 3431/* 3432 * Starting up. 3433 * VNET_SYSINIT is called for each existing vnet and each new vnet. 3434 */ 3435VNET_SYSINIT(vnet_pfsync_init, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER, 3436 vnet_pfsync_init, NULL); 3437 3438/* 3439 * Closing up shop. These are done in REVERSE ORDER, 3440 * Not called on reboot. 3441 * VNET_SYSUNINIT is called for each exiting vnet as it exits. 3442 */ 3443VNET_SYSUNINIT(vnet_pfsync_uninit, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER, 3444 vnet_pfsync_uninit, NULL); 3445static int 3446pfsync_modevent(module_t mod, int type, void *data) 3447{ 3448 int error = 0; 3449 3450 switch (type) { 3451 case MOD_LOAD: 3452#ifndef __FreeBSD__ 3453 pfsyncattach(0); 3454#endif 3455 break; 3456 case MOD_UNLOAD: 3457#ifndef __FreeBSD__ 3458 if_clone_detach(&pfsync_cloner); 3459#endif 3460 break; 3461 default: 3462 error = EINVAL; 3463 break; 3464 } 3465 3466 return error; 3467} 3468 3469static moduledata_t pfsync_mod = { 3470 "pfsync", 3471 pfsync_modevent, 3472 0 3473}; 3474 3475#define PFSYNC_MODVER 1 3476 3477DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 3478MODULE_VERSION(pfsync, PFSYNC_MODVER); 3479MODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); 3480#endif /* __FreeBSD__ */ 3481