1244769Sglebius/*- 2126258Smlaier * Copyright (c) 2002 Michael Shalayeff 3244769Sglebius * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org> 4126258Smlaier * All rights reserved. 5126258Smlaier * 6126258Smlaier * Redistribution and use in source and binary forms, with or without 7126258Smlaier * modification, are permitted provided that the following conditions 8126258Smlaier * are met: 9126258Smlaier * 1. Redistributions of source code must retain the above copyright 10126258Smlaier * notice, this list of conditions and the following disclaimer. 11126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright 12126258Smlaier * notice, this list of conditions and the following disclaimer in the 13126258Smlaier * documentation and/or other materials provided with the distribution. 14126258Smlaier * 15126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16126258Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17126258Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18126258Smlaier * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 19126258Smlaier * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20126258Smlaier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21126258Smlaier * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22126258Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23126258Smlaier * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24126258Smlaier * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 25126258Smlaier * THE POSSIBILITY OF SUCH DAMAGE. 26126258Smlaier */ 27126258Smlaier 28244769Sglebius/*- 29223637Sbz * Copyright (c) 2009 David Gwynne <dlg@openbsd.org> 30223637Sbz * 31223637Sbz * Permission to use, copy, modify, and distribute this software for any 32223637Sbz * purpose with or without fee is hereby granted, provided that the above 33223637Sbz * copyright notice and this permission notice appear in all copies. 34223637Sbz * 35223637Sbz * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 36223637Sbz * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 37223637Sbz * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 38223637Sbz * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 39223637Sbz * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 40223637Sbz * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 41223637Sbz * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 42223637Sbz */ 43223637Sbz 44228814Sglebius/* 45244769Sglebius * $OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $ 46244769Sglebius * 47228814Sglebius * Revisions picked from OpenBSD after revision 1.110 import: 48244185Sglebius * 1.119 - don't m_copydata() beyond the len of mbuf in pfsync_input() 49228814Sglebius * 1.118, 1.124, 1.148, 1.149, 1.151, 1.171 - fixes to bulk updates 50228815Sglebius * 1.120, 1.175 - use monotonic time_uptime 51228816Sglebius * 1.122 - reduce number of updates for non-TCP sessions 52244113Sglebius * 1.125, 1.127 - rewrite merge or stale processing 53229961Sglebius * 1.128 - cleanups 54232685Sglebius * 1.146 - bzero() mbuf before sparsely filling it with data 55229777Sglebius * 1.170 - SIOCSIFMTU checks 56233846Sglebius * 1.126, 1.142 - deferred packets processing 57233874Sglebius * 1.173 - correct expire time processing 58228814Sglebius */ 59228814Sglebius 60240233Sglebius#include <sys/cdefs.h> 61240233Sglebius__FBSDID("$FreeBSD$"); 62240233Sglebius 63126261Smlaier#include "opt_inet.h" 64126261Smlaier#include "opt_inet6.h" 65126261Smlaier#include "opt_pf.h" 66153110Sru 67126258Smlaier#include <sys/param.h> 68223637Sbz#include <sys/bus.h> 69240233Sglebius#include <sys/endian.h> 70223637Sbz#include <sys/interrupt.h> 71240233Sglebius#include <sys/kernel.h> 72240233Sglebius#include <sys/lock.h> 73126258Smlaier#include <sys/mbuf.h> 74129907Smlaier#include <sys/module.h> 75130613Smlaier#include <sys/mutex.h> 76240233Sglebius#include <sys/priv.h> 77229850Sglebius#include <sys/protosw.h> 78240233Sglebius#include <sys/socket.h> 79240233Sglebius#include <sys/sockio.h> 80223637Sbz#include <sys/sysctl.h> 81126258Smlaier 82240233Sglebius#include <net/bpf.h> 83126258Smlaier#include <net/if.h> 84130933Sbrooks#include <net/if_clone.h> 85126258Smlaier#include <net/if_types.h> 86240233Sglebius#include <net/pfvar.h> 87240233Sglebius#include <net/if_pfsync.h> 88223637Sbz 89240233Sglebius#include <netinet/if_ether.h> 90171168Smlaier#include <netinet/in.h> 91126258Smlaier#include <netinet/in_var.h> 92130613Smlaier#include <netinet/ip.h> 93240233Sglebius#include <netinet/ip_carp.h> 94130613Smlaier#include <netinet/ip_var.h> 95240233Sglebius#include <netinet/tcp.h> 96240233Sglebius#include <netinet/tcp_fsm.h> 97240233Sglebius#include <netinet/tcp_seq.h> 98126258Smlaier 99223637Sbz#define PFSYNC_MINPKT ( \ 100223637Sbz sizeof(struct ip) + \ 101223637Sbz sizeof(struct pfsync_header) + \ 102246822Sglebius sizeof(struct pfsync_subheader) ) 103126258Smlaier 104223637Sbzstruct pfsync_pkt { 105223637Sbz struct ip *ip; 106223637Sbz struct in_addr src; 107223637Sbz u_int8_t flags; 108223637Sbz}; 109223637Sbz 110240233Sglebiusstatic int pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *, 111240233Sglebius struct pfsync_state_peer *); 112240233Sglebiusstatic int pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int); 113240233Sglebiusstatic int pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int); 114240233Sglebiusstatic int pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int); 115240233Sglebiusstatic int pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int); 116240233Sglebiusstatic int pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int); 117240233Sglebiusstatic int pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int); 118240233Sglebiusstatic int pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int); 119240233Sglebiusstatic int pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int); 120240233Sglebiusstatic int pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int); 121240233Sglebiusstatic int pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int); 122240233Sglebiusstatic int pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int); 123240233Sglebiusstatic int pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int); 124223637Sbz 125240233Sglebiusstatic int (*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = { 126223637Sbz pfsync_in_clr, /* PFSYNC_ACT_CLR */ 127223637Sbz pfsync_in_ins, /* PFSYNC_ACT_INS */ 128223637Sbz pfsync_in_iack, /* PFSYNC_ACT_INS_ACK */ 129223637Sbz pfsync_in_upd, /* PFSYNC_ACT_UPD */ 130223637Sbz pfsync_in_upd_c, /* PFSYNC_ACT_UPD_C */ 131223637Sbz pfsync_in_ureq, /* PFSYNC_ACT_UPD_REQ */ 132223637Sbz pfsync_in_del, /* PFSYNC_ACT_DEL */ 133223637Sbz pfsync_in_del_c, /* PFSYNC_ACT_DEL_C */ 134223637Sbz pfsync_in_error, /* PFSYNC_ACT_INS_F */ 135223637Sbz pfsync_in_error, /* PFSYNC_ACT_DEL_F */ 136223637Sbz pfsync_in_bus, /* PFSYNC_ACT_BUS */ 137223637Sbz pfsync_in_tdb, /* PFSYNC_ACT_TDB */ 138223637Sbz pfsync_in_eof /* PFSYNC_ACT_EOF */ 139223637Sbz}; 140223637Sbz 141223637Sbzstruct pfsync_q { 142241056Sglebius void (*write)(struct pf_state *, void *); 143223637Sbz size_t len; 144223637Sbz u_int8_t action; 145223637Sbz}; 146223637Sbz 147223637Sbz/* we have one of these for every PFSYNC_S_ */ 148241056Sglebiusstatic void pfsync_out_state(struct pf_state *, void *); 149241056Sglebiusstatic void pfsync_out_iack(struct pf_state *, void *); 150241056Sglebiusstatic void pfsync_out_upd_c(struct pf_state *, void *); 151241056Sglebiusstatic void pfsync_out_del(struct pf_state *, void *); 152223637Sbz 153240233Sglebiusstatic struct pfsync_q pfsync_qs[] = { 154223637Sbz { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_INS }, 155223637Sbz { pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK }, 156223637Sbz { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_UPD }, 157223637Sbz { pfsync_out_upd_c, sizeof(struct pfsync_upd_c), PFSYNC_ACT_UPD_C }, 158223637Sbz { pfsync_out_del, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C } 159223637Sbz}; 160223637Sbz 161240233Sglebiusstatic void pfsync_q_ins(struct pf_state *, int); 162240233Sglebiusstatic void pfsync_q_del(struct pf_state *); 163223637Sbz 164240233Sglebiusstatic void pfsync_update_state(struct pf_state *); 165240233Sglebius 166223637Sbzstruct pfsync_upd_req_item { 167223637Sbz TAILQ_ENTRY(pfsync_upd_req_item) ur_entry; 168223637Sbz struct pfsync_upd_req ur_msg; 169223637Sbz}; 170223637Sbz 171223637Sbzstruct pfsync_deferral { 172240233Sglebius struct pfsync_softc *pd_sc; 173240233Sglebius TAILQ_ENTRY(pfsync_deferral) pd_entry; 174240233Sglebius u_int pd_refs; 175240233Sglebius struct callout pd_tmo; 176240233Sglebius 177240233Sglebius struct pf_state *pd_st; 178240233Sglebius struct mbuf *pd_m; 179223637Sbz}; 180126258Smlaier 181223637Sbzstruct pfsync_softc { 182240233Sglebius /* Configuration */ 183223637Sbz struct ifnet *sc_ifp; 184223637Sbz struct ifnet *sc_sync_if; 185240233Sglebius struct ip_moptions sc_imo; 186240233Sglebius struct in_addr sc_sync_peer; 187240233Sglebius uint32_t sc_flags; 188240233Sglebius#define PFSYNCF_OK 0x00000001 189240233Sglebius#define PFSYNCF_DEFER 0x00000002 190240233Sglebius#define PFSYNCF_PUSH 0x00000004 191240233Sglebius uint8_t sc_maxupdates; 192240233Sglebius struct ip sc_template; 193240233Sglebius struct callout sc_tmo; 194240233Sglebius struct mtx sc_mtx; 195223637Sbz 196240233Sglebius /* Queued data */ 197240233Sglebius size_t sc_len; 198240233Sglebius TAILQ_HEAD(, pf_state) sc_qs[PFSYNC_S_COUNT]; 199240233Sglebius TAILQ_HEAD(, pfsync_upd_req_item) sc_upd_req_list; 200240233Sglebius TAILQ_HEAD(, pfsync_deferral) sc_deferrals; 201240233Sglebius u_int sc_deferred; 202223637Sbz void *sc_plus; 203240233Sglebius size_t sc_pluslen; 204223637Sbz 205240233Sglebius /* Bulk update info */ 206240233Sglebius struct mtx sc_bulk_mtx; 207240233Sglebius uint32_t sc_ureq_sent; 208240233Sglebius int sc_bulk_tries; 209240233Sglebius uint32_t sc_ureq_received; 210240233Sglebius int sc_bulk_hashid; 211240233Sglebius uint64_t sc_bulk_stateid; 212240233Sglebius uint32_t sc_bulk_creatorid; 213240233Sglebius struct callout sc_bulk_tmo; 214240233Sglebius struct callout sc_bulkfail_tmo; 215240233Sglebius}; 216223637Sbz 217240233Sglebius#define PFSYNC_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 218240233Sglebius#define PFSYNC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 219240233Sglebius#define PFSYNC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) 220223637Sbz 221240233Sglebius#define PFSYNC_BLOCK(sc) mtx_lock(&(sc)->sc_bulk_mtx) 222240233Sglebius#define PFSYNC_BUNLOCK(sc) mtx_unlock(&(sc)->sc_bulk_mtx) 223240233Sglebius#define PFSYNC_BLOCK_ASSERT(sc) mtx_assert(&(sc)->sc_bulk_mtx, MA_OWNED) 224223637Sbz 225241610Sglebiusstatic const char pfsyncname[] = "pfsync"; 226241610Sglebiusstatic MALLOC_DEFINE(M_PFSYNC, pfsyncname, "pfsync(4) data"); 227223637Sbzstatic VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; 228223637Sbz#define V_pfsyncif VNET(pfsyncif) 229229850Sglebiusstatic VNET_DEFINE(void *, pfsync_swi_cookie) = NULL; 230229850Sglebius#define V_pfsync_swi_cookie VNET(pfsync_swi_cookie) 231223637Sbzstatic VNET_DEFINE(struct pfsyncstats, pfsyncstats); 232223637Sbz#define V_pfsyncstats VNET(pfsyncstats) 233228736Sglebiusstatic VNET_DEFINE(int, pfsync_carp_adj) = CARP_MAXSKEW; 234228736Sglebius#define V_pfsync_carp_adj VNET(pfsync_carp_adj) 235223637Sbz 236240233Sglebiusstatic void pfsync_timeout(void *); 237240233Sglebiusstatic void pfsync_push(struct pfsync_softc *); 238229850Sglebiusstatic void pfsyncintr(void *); 239240233Sglebiusstatic int pfsync_multicast_setup(struct pfsync_softc *, struct ifnet *, 240240233Sglebius void *); 241229850Sglebiusstatic void pfsync_multicast_cleanup(struct pfsync_softc *); 242241057Sglebiusstatic void pfsync_pointers_init(void); 243241057Sglebiusstatic void pfsync_pointers_uninit(void); 244229850Sglebiusstatic int pfsync_init(void); 245229850Sglebiusstatic void pfsync_uninit(void); 246229850Sglebius 247223637SbzSYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC"); 248223637SbzSYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW, 249223637Sbz &VNET_NAME(pfsyncstats), pfsyncstats, 250223637Sbz "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); 251228736SglebiusSYSCTL_INT(_net_pfsync, OID_AUTO, carp_demotion_factor, CTLFLAG_RW, 252228736Sglebius &VNET_NAME(pfsync_carp_adj), 0, "pfsync's CARP demotion factor adjustment"); 253223637Sbz 254240233Sglebiusstatic int pfsync_clone_create(struct if_clone *, int, caddr_t); 255240233Sglebiusstatic void pfsync_clone_destroy(struct ifnet *); 256240233Sglebiusstatic int pfsync_alloc_scrub_memory(struct pfsync_state_peer *, 257240233Sglebius struct pf_state_peer *); 258249925Sglebiusstatic int pfsyncoutput(struct ifnet *, struct mbuf *, 259249925Sglebius const struct sockaddr *, struct route *); 260240233Sglebiusstatic int pfsyncioctl(struct ifnet *, u_long, caddr_t); 261126258Smlaier 262240233Sglebiusstatic int pfsync_defer(struct pf_state *, struct mbuf *); 263240233Sglebiusstatic void pfsync_undefer(struct pfsync_deferral *, int); 264240233Sglebiusstatic void pfsync_undefer_state(struct pf_state *, int); 265240233Sglebiusstatic void pfsync_defer_tmo(void *); 266223637Sbz 267240233Sglebiusstatic void pfsync_request_update(u_int32_t, u_int64_t); 268240233Sglebiusstatic void pfsync_update_state_req(struct pf_state *); 269223637Sbz 270240233Sglebiusstatic void pfsync_drop(struct pfsync_softc *); 271240233Sglebiusstatic void pfsync_sendout(int); 272240233Sglebiusstatic void pfsync_send_plus(void *, size_t); 273223637Sbz 274240233Sglebiusstatic void pfsync_bulk_start(void); 275240233Sglebiusstatic void pfsync_bulk_status(u_int8_t); 276240233Sglebiusstatic void pfsync_bulk_update(void *); 277240233Sglebiusstatic void pfsync_bulk_fail(void *); 278223637Sbz 279240233Sglebius#ifdef IPSEC 280240233Sglebiusstatic void pfsync_update_net_tdb(struct pfsync_tdb *); 281167710Sbms#endif 282126258Smlaier 283223637Sbz#define PFSYNC_MAX_BULKTRIES 12 284126258Smlaier 285241610SglebiusVNET_DEFINE(struct if_clone *, pfsync_cloner); 286241610Sglebius#define V_pfsync_cloner VNET(pfsync_cloner) 287126261Smlaier 288240233Sglebiusstatic int 289171168Smlaierpfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) 290126261Smlaier{ 291223637Sbz struct pfsync_softc *sc; 292130613Smlaier struct ifnet *ifp; 293223637Sbz int q; 294126261Smlaier 295171168Smlaier if (unit != 0) 296171168Smlaier return (EINVAL); 297171168Smlaier 298229850Sglebius sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO); 299240233Sglebius sc->sc_flags |= PFSYNCF_OK; 300223637Sbz 301223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) 302223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 303223637Sbz 304223637Sbz TAILQ_INIT(&sc->sc_upd_req_list); 305223637Sbz TAILQ_INIT(&sc->sc_deferrals); 306171168Smlaier 307223637Sbz sc->sc_len = PFSYNC_MINPKT; 308223637Sbz sc->sc_maxupdates = 128; 309223637Sbz 310223637Sbz ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); 311147256Sbrooks if (ifp == NULL) { 312229850Sglebius free(sc, M_PFSYNC); 313147256Sbrooks return (ENOSPC); 314147256Sbrooks } 315241610Sglebius if_initname(ifp, pfsyncname, unit); 316223637Sbz ifp->if_softc = sc; 317130613Smlaier ifp->if_ioctl = pfsyncioctl; 318130613Smlaier ifp->if_output = pfsyncoutput; 319171168Smlaier ifp->if_type = IFT_PFSYNC; 320130613Smlaier ifp->if_snd.ifq_maxlen = ifqmaxlen; 321223637Sbz ifp->if_hdrlen = sizeof(struct pfsync_header); 322229777Sglebius ifp->if_mtu = ETHERMTU; 323241610Sglebius mtx_init(&sc->sc_mtx, pfsyncname, NULL, MTX_DEF); 324240233Sglebius mtx_init(&sc->sc_bulk_mtx, "pfsync bulk", NULL, MTX_DEF); 325223637Sbz callout_init(&sc->sc_tmo, CALLOUT_MPSAFE); 326240233Sglebius callout_init_mtx(&sc->sc_bulk_tmo, &sc->sc_bulk_mtx, 0); 327240233Sglebius callout_init_mtx(&sc->sc_bulkfail_tmo, &sc->sc_bulk_mtx, 0); 328223637Sbz 329141584Smlaier if_attach(ifp); 330126261Smlaier 331141584Smlaier bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); 332126261Smlaier 333223637Sbz V_pfsyncif = sc; 334223637Sbz 335126261Smlaier return (0); 336126261Smlaier} 337171168Smlaier 338240233Sglebiusstatic void 339171168Smlaierpfsync_clone_destroy(struct ifnet *ifp) 340126258Smlaier{ 341223637Sbz struct pfsync_softc *sc = ifp->if_softc; 342223637Sbz 343240233Sglebius /* 344240233Sglebius * At this stage, everything should have already been 345240233Sglebius * cleared by pfsync_uninit(), and we have only to 346240233Sglebius * drain callouts. 347240233Sglebius */ 348240233Sglebius while (sc->sc_deferred > 0) { 349240233Sglebius struct pfsync_deferral *pd = TAILQ_FIRST(&sc->sc_deferrals); 350240233Sglebius 351240233Sglebius TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 352240233Sglebius sc->sc_deferred--; 353240233Sglebius if (callout_stop(&pd->pd_tmo)) { 354240233Sglebius pf_release_state(pd->pd_st); 355240233Sglebius m_freem(pd->pd_m); 356240233Sglebius free(pd, M_PFSYNC); 357240233Sglebius } else { 358240233Sglebius pd->pd_refs++; 359240233Sglebius callout_drain(&pd->pd_tmo); 360240233Sglebius free(pd, M_PFSYNC); 361240233Sglebius } 362240233Sglebius } 363240233Sglebius 364240233Sglebius callout_drain(&sc->sc_tmo); 365240233Sglebius callout_drain(&sc->sc_bulkfail_tmo); 366240233Sglebius callout_drain(&sc->sc_bulk_tmo); 367240233Sglebius 368240233Sglebius if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 369228736Sglebius (*carp_demote_adj_p)(-V_pfsync_carp_adj, "pfsync destroy"); 370171168Smlaier bpfdetach(ifp); 371171168Smlaier if_detach(ifp); 372223637Sbz 373223637Sbz pfsync_drop(sc); 374223637Sbz 375171168Smlaier if_free(ifp); 376229850Sglebius if (sc->sc_imo.imo_membership) 377229850Sglebius pfsync_multicast_cleanup(sc); 378240233Sglebius mtx_destroy(&sc->sc_mtx); 379240233Sglebius mtx_destroy(&sc->sc_bulk_mtx); 380229850Sglebius free(sc, M_PFSYNC); 381223637Sbz 382223637Sbz V_pfsyncif = NULL; 383126258Smlaier} 384126258Smlaier 385240233Sglebiusstatic int 386171168Smlaierpfsync_alloc_scrub_memory(struct pfsync_state_peer *s, 387171168Smlaier struct pf_state_peer *d) 388130613Smlaier{ 389171168Smlaier if (s->scrub.scrub_flag && d->scrub == NULL) { 390240233Sglebius d->scrub = uma_zalloc(V_pf_state_scrub_z, M_NOWAIT | M_ZERO); 391171168Smlaier if (d->scrub == NULL) 392171168Smlaier return (ENOMEM); 393171168Smlaier } 394171168Smlaier 395171168Smlaier return (0); 396171168Smlaier} 397171168Smlaier 398223637Sbz 399240233Sglebiusstatic int 400223637Sbzpfsync_state_import(struct pfsync_state *sp, u_int8_t flags) 401171168Smlaier{ 402240233Sglebius struct pfsync_softc *sc = V_pfsyncif; 403130613Smlaier struct pf_state *st = NULL; 404223637Sbz struct pf_state_key *skw = NULL, *sks = NULL; 405130613Smlaier struct pf_rule *r = NULL; 406130613Smlaier struct pfi_kif *kif; 407223637Sbz int error; 408130613Smlaier 409240233Sglebius PF_RULES_RASSERT(); 410226544Sbz 411250518Sglebius if (sp->creatorid == 0) { 412250518Sglebius if (V_pf_status.debug >= PF_DEBUG_MISC) 413250518Sglebius printf("%s: invalid creator id: %08x\n", __func__, 414250518Sglebius ntohl(sp->creatorid)); 415130613Smlaier return (EINVAL); 416130613Smlaier } 417130613Smlaier 418240233Sglebius if ((kif = pfi_kif_find(sp->ifname)) == NULL) { 419223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 420240233Sglebius printf("%s: unknown interface: %s\n", __func__, 421240233Sglebius sp->ifname); 422223637Sbz if (flags & PFSYNC_SI_IOCTL) 423223637Sbz return (EINVAL); 424223637Sbz return (0); /* skip this state */ 425130613Smlaier } 426130613Smlaier 427130613Smlaier /* 428223637Sbz * If the ruleset checksums match or the state is coming from the ioctl, 429223637Sbz * it's safe to associate the state with the rule of that number. 430130613Smlaier */ 431223637Sbz if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && 432223637Sbz (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < 433223637Sbz pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) 434171168Smlaier r = pf_main_ruleset.rules[ 435171168Smlaier PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; 436171168Smlaier else 437223637Sbz r = &V_pf_default_rule; 438130613Smlaier 439223637Sbz if ((r->max_states && r->states_cur >= r->max_states)) 440223637Sbz goto cleanup; 441130613Smlaier 442240233Sglebius /* 443240233Sglebius * XXXGL: consider M_WAITOK in ioctl path after. 444240233Sglebius */ 445240233Sglebius if ((st = uma_zalloc(V_pf_state_z, M_NOWAIT | M_ZERO)) == NULL) 446223637Sbz goto cleanup; 447130613Smlaier 448240233Sglebius if ((skw = uma_zalloc(V_pf_state_key_z, M_NOWAIT)) == NULL) 449223637Sbz goto cleanup; 450145836Smlaier 451223637Sbz if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], 452223637Sbz &sp->key[PF_SK_STACK].addr[0], sp->af) || 453223637Sbz PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], 454223637Sbz &sp->key[PF_SK_STACK].addr[1], sp->af) || 455223637Sbz sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || 456223637Sbz sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) { 457240233Sglebius sks = uma_zalloc(V_pf_state_key_z, M_NOWAIT); 458240233Sglebius if (sks == NULL) 459223637Sbz goto cleanup; 460223637Sbz } else 461223637Sbz sks = skw; 462130613Smlaier 463223637Sbz /* allocate memory for scrub info */ 464223637Sbz if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || 465223637Sbz pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) 466223637Sbz goto cleanup; 467223637Sbz 468223637Sbz /* copy to state key(s) */ 469223637Sbz skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; 470223637Sbz skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; 471223637Sbz skw->port[0] = sp->key[PF_SK_WIRE].port[0]; 472223637Sbz skw->port[1] = sp->key[PF_SK_WIRE].port[1]; 473223637Sbz skw->proto = sp->proto; 474223637Sbz skw->af = sp->af; 475223637Sbz if (sks != skw) { 476223637Sbz sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; 477223637Sbz sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; 478223637Sbz sks->port[0] = sp->key[PF_SK_STACK].port[0]; 479223637Sbz sks->port[1] = sp->key[PF_SK_STACK].port[1]; 480223637Sbz sks->proto = sp->proto; 481223637Sbz sks->af = sp->af; 482223637Sbz } 483223637Sbz 484223637Sbz /* copy to state */ 485130613Smlaier bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); 486228815Sglebius st->creation = time_uptime - ntohl(sp->creation); 487240233Sglebius st->expire = time_uptime; 488223637Sbz if (sp->expire) { 489233874Sglebius uint32_t timeout; 490233874Sglebius 491233874Sglebius timeout = r->timeout[sp->timeout]; 492233874Sglebius if (!timeout) 493233917Sae timeout = V_pf_default_rule.timeout[sp->timeout]; 494233874Sglebius 495233874Sglebius /* sp->expire may have been adaptively scaled by export. */ 496233874Sglebius st->expire -= timeout - ntohl(sp->expire); 497223637Sbz } 498223637Sbz 499130613Smlaier st->direction = sp->direction; 500130613Smlaier st->log = sp->log; 501130613Smlaier st->timeout = sp->timeout; 502200930Sdelphij st->state_flags = sp->state_flags; 503130613Smlaier 504240233Sglebius st->id = sp->id; 505130613Smlaier st->creatorid = sp->creatorid; 506223637Sbz pf_state_peer_ntoh(&sp->src, &st->src); 507223637Sbz pf_state_peer_ntoh(&sp->dst, &st->dst); 508130613Smlaier 509223637Sbz st->rule.ptr = r; 510223637Sbz st->nat_rule.ptr = NULL; 511223637Sbz st->anchor.ptr = NULL; 512223637Sbz st->rt_kif = NULL; 513223637Sbz 514228815Sglebius st->pfsync_time = time_uptime; 515223637Sbz st->sync_state = PFSYNC_S_NONE; 516223637Sbz 517223637Sbz /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ 518223637Sbz r->states_cur++; 519223637Sbz r->states_tot++; 520223637Sbz 521240233Sglebius if (!(flags & PFSYNC_SI_IOCTL)) 522240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 523223637Sbz 524223637Sbz if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { 525145836Smlaier /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ 526223637Sbz r->states_cur--; 527223637Sbz goto cleanup_state; 528223637Sbz } 529223637Sbz 530240233Sglebius if (!(flags & PFSYNC_SI_IOCTL)) { 531240233Sglebius st->state_flags &= ~PFSTATE_NOSYNC; 532240233Sglebius if (st->state_flags & PFSTATE_ACK) { 533223637Sbz pfsync_q_ins(st, PFSYNC_S_IACK); 534240233Sglebius pfsync_push(sc); 535223637Sbz } 536223637Sbz } 537240233Sglebius st->state_flags &= ~PFSTATE_ACK; 538240233Sglebius PF_STATE_UNLOCK(st); 539223637Sbz 540223637Sbz return (0); 541223637Sbz 542223637Sbzcleanup: 543223637Sbz error = ENOMEM; 544223637Sbz if (skw == sks) 545223637Sbz sks = NULL; 546223637Sbz if (skw != NULL) 547240233Sglebius uma_zfree(V_pf_state_key_z, skw); 548223637Sbz if (sks != NULL) 549240233Sglebius uma_zfree(V_pf_state_key_z, sks); 550223637Sbz 551240233Sglebiuscleanup_state: /* pf_state_insert() frees the state keys. */ 552223637Sbz if (st) { 553171168Smlaier if (st->dst.scrub) 554240233Sglebius uma_zfree(V_pf_state_scrub_z, st->dst.scrub); 555223637Sbz if (st->src.scrub) 556240233Sglebius uma_zfree(V_pf_state_scrub_z, st->src.scrub); 557240233Sglebius uma_zfree(V_pf_state_z, st); 558130613Smlaier } 559223637Sbz return (error); 560130613Smlaier} 561130613Smlaier 562240233Sglebiusstatic void 563130613Smlaierpfsync_input(struct mbuf *m, __unused int off) 564130613Smlaier{ 565223637Sbz struct pfsync_softc *sc = V_pfsyncif; 566223637Sbz struct pfsync_pkt pkt; 567130613Smlaier struct ip *ip = mtod(m, struct ip *); 568130613Smlaier struct pfsync_header *ph; 569223637Sbz struct pfsync_subheader subh; 570130613Smlaier 571244185Sglebius int offset, len; 572223637Sbz int rv; 573240233Sglebius uint16_t count; 574130613Smlaier 575223637Sbz V_pfsyncstats.pfsyncs_ipackets++; 576223637Sbz 577240233Sglebius /* Verify that we have a sync interface configured. */ 578240233Sglebius if (!sc || !sc->sc_sync_if || !V_pf_status.running || 579240233Sglebius (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 580130613Smlaier goto done; 581130613Smlaier 582130613Smlaier /* verify that the packet came in on the right interface */ 583223637Sbz if (sc->sc_sync_if != m->m_pkthdr.rcvif) { 584223637Sbz V_pfsyncstats.pfsyncs_badif++; 585130613Smlaier goto done; 586130613Smlaier } 587130613Smlaier 588223637Sbz sc->sc_ifp->if_ipackets++; 589223637Sbz sc->sc_ifp->if_ibytes += m->m_pkthdr.len; 590223637Sbz /* verify that the IP TTL is 255. */ 591130613Smlaier if (ip->ip_ttl != PFSYNC_DFLTTL) { 592223637Sbz V_pfsyncstats.pfsyncs_badttl++; 593130613Smlaier goto done; 594130613Smlaier } 595130613Smlaier 596223637Sbz offset = ip->ip_hl << 2; 597223637Sbz if (m->m_pkthdr.len < offset + sizeof(*ph)) { 598223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 599130613Smlaier goto done; 600130613Smlaier } 601130613Smlaier 602223637Sbz if (offset + sizeof(*ph) > m->m_len) { 603223637Sbz if (m_pullup(m, offset + sizeof(*ph)) == NULL) { 604223637Sbz V_pfsyncstats.pfsyncs_hdrops++; 605223637Sbz return; 606130613Smlaier } 607130613Smlaier ip = mtod(m, struct ip *); 608130613Smlaier } 609223637Sbz ph = (struct pfsync_header *)((char *)ip + offset); 610130613Smlaier 611130613Smlaier /* verify the version */ 612130613Smlaier if (ph->version != PFSYNC_VERSION) { 613223637Sbz V_pfsyncstats.pfsyncs_badver++; 614130613Smlaier goto done; 615130613Smlaier } 616130613Smlaier 617244185Sglebius len = ntohs(ph->len) + offset; 618244185Sglebius if (m->m_pkthdr.len < len) { 619244202Sglebius V_pfsyncstats.pfsyncs_badlen++; 620244185Sglebius goto done; 621244185Sglebius } 622244185Sglebius 623130613Smlaier /* Cheaper to grab this now than having to mess with mbufs later */ 624223637Sbz pkt.ip = ip; 625223637Sbz pkt.src = ip->ip_src; 626223637Sbz pkt.flags = 0; 627130613Smlaier 628240233Sglebius /* 629240233Sglebius * Trusting pf_chksum during packet processing, as well as seeking 630240233Sglebius * in interface name tree, require holding PF_RULES_RLOCK(). 631240233Sglebius */ 632240233Sglebius PF_RULES_RLOCK(); 633223637Sbz if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) 634223637Sbz pkt.flags |= PFSYNC_SI_CKSUM; 635171168Smlaier 636223637Sbz offset += sizeof(*ph); 637244185Sglebius while (offset <= len - sizeof(subh)) { 638223637Sbz m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); 639223637Sbz offset += sizeof(subh); 640223637Sbz 641223637Sbz if (subh.action >= PFSYNC_ACT_MAX) { 642223637Sbz V_pfsyncstats.pfsyncs_badact++; 643240233Sglebius PF_RULES_RUNLOCK(); 644223637Sbz goto done; 645130613Smlaier } 646130613Smlaier 647240233Sglebius count = ntohs(subh.count); 648240233Sglebius V_pfsyncstats.pfsyncs_iacts[subh.action] += count; 649240233Sglebius rv = (*pfsync_acts[subh.action])(&pkt, m, offset, count); 650240233Sglebius if (rv == -1) { 651240233Sglebius PF_RULES_RUNLOCK(); 652223637Sbz return; 653240233Sglebius } 654223637Sbz 655223637Sbz offset += rv; 656223637Sbz } 657240233Sglebius PF_RULES_RUNLOCK(); 658223637Sbz 659223637Sbzdone: 660223637Sbz m_freem(m); 661223637Sbz} 662223637Sbz 663240233Sglebiusstatic int 664223637Sbzpfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 665223637Sbz{ 666223637Sbz struct pfsync_clr *clr; 667223637Sbz struct mbuf *mp; 668223637Sbz int len = sizeof(*clr) * count; 669223637Sbz int i, offp; 670223637Sbz u_int32_t creatorid; 671223637Sbz 672223637Sbz mp = m_pulldown(m, offset, len, &offp); 673223637Sbz if (mp == NULL) { 674223637Sbz V_pfsyncstats.pfsyncs_badlen++; 675223637Sbz return (-1); 676223637Sbz } 677223637Sbz clr = (struct pfsync_clr *)(mp->m_data + offp); 678223637Sbz 679223637Sbz for (i = 0; i < count; i++) { 680223637Sbz creatorid = clr[i].creatorid; 681223637Sbz 682240233Sglebius if (clr[i].ifname[0] != '\0' && 683240233Sglebius pfi_kif_find(clr[i].ifname) == NULL) 684240233Sglebius continue; 685223637Sbz 686240233Sglebius for (int i = 0; i <= V_pf_hashmask; i++) { 687240233Sglebius struct pf_idhash *ih = &V_pf_idhash[i]; 688240233Sglebius struct pf_state *s; 689240233Sglebiusrelock: 690240233Sglebius PF_HASHROW_LOCK(ih); 691240233Sglebius LIST_FOREACH(s, &ih->states, entry) { 692240233Sglebius if (s->creatorid == creatorid) { 693240233Sglebius s->state_flags |= PFSTATE_NOSYNC; 694240233Sglebius pf_unlink_state(s, PF_ENTER_LOCKED); 695240233Sglebius goto relock; 696145836Smlaier } 697130613Smlaier } 698240233Sglebius PF_HASHROW_UNLOCK(ih); 699130613Smlaier } 700223637Sbz } 701130613Smlaier 702223637Sbz return (len); 703223637Sbz} 704223637Sbz 705240233Sglebiusstatic int 706223637Sbzpfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 707223637Sbz{ 708223637Sbz struct mbuf *mp; 709223637Sbz struct pfsync_state *sa, *sp; 710223637Sbz int len = sizeof(*sp) * count; 711223637Sbz int i, offp; 712223637Sbz 713223637Sbz mp = m_pulldown(m, offset, len, &offp); 714223637Sbz if (mp == NULL) { 715223637Sbz V_pfsyncstats.pfsyncs_badlen++; 716223637Sbz return (-1); 717130613Smlaier } 718223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 719130613Smlaier 720223637Sbz for (i = 0; i < count; i++) { 721223637Sbz sp = &sa[i]; 722130613Smlaier 723240233Sglebius /* Check for invalid values. */ 724223637Sbz if (sp->timeout >= PFTM_MAX || 725223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 726223637Sbz sp->dst.state > PF_TCPS_PROXY_DST || 727223637Sbz sp->direction > PF_OUT || 728223637Sbz (sp->af != AF_INET && sp->af != AF_INET6)) { 729240233Sglebius if (V_pf_status.debug >= PF_DEBUG_MISC) 730240233Sglebius printf("%s: invalid value\n", __func__); 731223637Sbz V_pfsyncstats.pfsyncs_badval++; 732223637Sbz continue; 733130613Smlaier } 734223637Sbz 735240233Sglebius if (pfsync_state_import(sp, pkt->flags) == ENOMEM) 736240233Sglebius /* Drop out, but process the rest of the actions. */ 737223637Sbz break; 738223637Sbz } 739130613Smlaier 740223637Sbz return (len); 741223637Sbz} 742223637Sbz 743240233Sglebiusstatic int 744223637Sbzpfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 745223637Sbz{ 746223637Sbz struct pfsync_ins_ack *ia, *iaa; 747223637Sbz struct pf_state *st; 748223637Sbz 749223637Sbz struct mbuf *mp; 750223637Sbz int len = count * sizeof(*ia); 751223637Sbz int offp, i; 752223637Sbz 753223637Sbz mp = m_pulldown(m, offset, len, &offp); 754223637Sbz if (mp == NULL) { 755223637Sbz V_pfsyncstats.pfsyncs_badlen++; 756223637Sbz return (-1); 757223637Sbz } 758223637Sbz iaa = (struct pfsync_ins_ack *)(mp->m_data + offp); 759223637Sbz 760223637Sbz for (i = 0; i < count; i++) { 761223637Sbz ia = &iaa[i]; 762145836Smlaier 763240233Sglebius st = pf_find_state_byid(ia->id, ia->creatorid); 764223637Sbz if (st == NULL) 765223637Sbz continue; 766130613Smlaier 767240233Sglebius if (st->state_flags & PFSTATE_ACK) { 768240233Sglebius PFSYNC_LOCK(V_pfsyncif); 769240233Sglebius pfsync_undefer_state(st, 0); 770240233Sglebius PFSYNC_UNLOCK(V_pfsyncif); 771240233Sglebius } 772240233Sglebius PF_STATE_UNLOCK(st); 773223637Sbz } 774130613Smlaier /* 775223637Sbz * XXX this is not yet implemented, but we know the size of the 776223637Sbz * message so we can skip it. 777130613Smlaier */ 778130613Smlaier 779223637Sbz return (count * sizeof(struct pfsync_ins_ack)); 780223637Sbz} 781223637Sbz 782240233Sglebiusstatic int 783223637Sbzpfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src, 784223637Sbz struct pfsync_state_peer *dst) 785223637Sbz{ 786242694Sglebius int sync = 0; 787223637Sbz 788240233Sglebius PF_STATE_LOCK_ASSERT(st); 789240233Sglebius 790223637Sbz /* 791223637Sbz * The state should never go backwards except 792223637Sbz * for syn-proxy states. Neither should the 793223637Sbz * sequence window slide backwards. 794223637Sbz */ 795242694Sglebius if ((st->src.state > src->state && 796223637Sbz (st->src.state < PF_TCPS_PROXY_SRC || 797242694Sglebius src->state >= PF_TCPS_PROXY_SRC)) || 798244113Sglebius 799244113Sglebius (st->src.state == src->state && 800244113Sglebius SEQ_GT(st->src.seqlo, ntohl(src->seqlo)))) 801242694Sglebius sync++; 802242694Sglebius else 803223637Sbz pf_state_peer_ntoh(src, &st->src); 804223637Sbz 805244113Sglebius if ((st->dst.state > dst->state) || 806244113Sglebius 807242694Sglebius (st->dst.state >= TCPS_SYN_SENT && 808242694Sglebius SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo)))) 809242694Sglebius sync++; 810242694Sglebius else 811242694Sglebius pf_state_peer_ntoh(dst, &st->dst); 812242694Sglebius 813242694Sglebius return (sync); 814223637Sbz} 815223637Sbz 816240233Sglebiusstatic int 817223637Sbzpfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 818223637Sbz{ 819240233Sglebius struct pfsync_softc *sc = V_pfsyncif; 820223637Sbz struct pfsync_state *sa, *sp; 821223637Sbz struct pf_state *st; 822242694Sglebius int sync; 823223637Sbz 824223637Sbz struct mbuf *mp; 825223637Sbz int len = count * sizeof(*sp); 826223637Sbz int offp, i; 827223637Sbz 828223637Sbz mp = m_pulldown(m, offset, len, &offp); 829223637Sbz if (mp == NULL) { 830223637Sbz V_pfsyncstats.pfsyncs_badlen++; 831223637Sbz return (-1); 832223637Sbz } 833223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 834223637Sbz 835223637Sbz for (i = 0; i < count; i++) { 836223637Sbz sp = &sa[i]; 837130613Smlaier 838223637Sbz /* check for invalid values */ 839223637Sbz if (sp->timeout >= PFTM_MAX || 840223637Sbz sp->src.state > PF_TCPS_PROXY_DST || 841223637Sbz sp->dst.state > PF_TCPS_PROXY_DST) { 842223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 843223637Sbz printf("pfsync_input: PFSYNC_ACT_UPD: " 844223637Sbz "invalid value\n"); 845130613Smlaier } 846223637Sbz V_pfsyncstats.pfsyncs_badval++; 847223637Sbz continue; 848130613Smlaier } 849223637Sbz 850240233Sglebius st = pf_find_state_byid(sp->id, sp->creatorid); 851223637Sbz if (st == NULL) { 852223637Sbz /* insert the update */ 853223637Sbz if (pfsync_state_import(sp, 0)) 854223637Sbz V_pfsyncstats.pfsyncs_badstate++; 855223637Sbz continue; 856223637Sbz } 857223637Sbz 858240233Sglebius if (st->state_flags & PFSTATE_ACK) { 859240233Sglebius PFSYNC_LOCK(sc); 860240233Sglebius pfsync_undefer_state(st, 1); 861240233Sglebius PFSYNC_UNLOCK(sc); 862240233Sglebius } 863223637Sbz 864242694Sglebius if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) 865242694Sglebius sync = pfsync_upd_tcp(st, &sp->src, &sp->dst); 866223637Sbz else { 867242694Sglebius sync = 0; 868242694Sglebius 869223637Sbz /* 870223637Sbz * Non-TCP protocol state machine always go 871223637Sbz * forwards 872223637Sbz */ 873223637Sbz if (st->src.state > sp->src.state) 874242694Sglebius sync++; 875242694Sglebius else 876242694Sglebius pf_state_peer_ntoh(&sp->src, &st->src); 877242694Sglebius if (st->dst.state > sp->dst.state) 878242694Sglebius sync++; 879242694Sglebius else 880242694Sglebius pf_state_peer_ntoh(&sp->dst, &st->dst); 881223637Sbz } 882242694Sglebius if (sync < 2) { 883242694Sglebius pfsync_alloc_scrub_memory(&sp->dst, &st->dst); 884242694Sglebius pf_state_peer_ntoh(&sp->dst, &st->dst); 885242694Sglebius st->expire = time_uptime; 886242694Sglebius st->timeout = sp->timeout; 887242694Sglebius } 888242694Sglebius st->pfsync_time = time_uptime; 889223637Sbz 890242694Sglebius if (sync) { 891223637Sbz V_pfsyncstats.pfsyncs_stale++; 892130613Smlaier 893223637Sbz pfsync_update_state(st); 894240233Sglebius PF_STATE_UNLOCK(st); 895240233Sglebius PFSYNC_LOCK(sc); 896240233Sglebius pfsync_push(sc); 897240233Sglebius PFSYNC_UNLOCK(sc); 898223637Sbz continue; 899130613Smlaier } 900240233Sglebius PF_STATE_UNLOCK(st); 901223637Sbz } 902130613Smlaier 903223637Sbz return (len); 904223637Sbz} 905223637Sbz 906240233Sglebiusstatic int 907223637Sbzpfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 908223637Sbz{ 909240233Sglebius struct pfsync_softc *sc = V_pfsyncif; 910223637Sbz struct pfsync_upd_c *ua, *up; 911223637Sbz struct pf_state *st; 912223637Sbz int len = count * sizeof(*up); 913242694Sglebius int sync; 914223637Sbz struct mbuf *mp; 915223637Sbz int offp, i; 916223637Sbz 917223637Sbz mp = m_pulldown(m, offset, len, &offp); 918223637Sbz if (mp == NULL) { 919223637Sbz V_pfsyncstats.pfsyncs_badlen++; 920223637Sbz return (-1); 921223637Sbz } 922223637Sbz ua = (struct pfsync_upd_c *)(mp->m_data + offp); 923223637Sbz 924223637Sbz for (i = 0; i < count; i++) { 925223637Sbz up = &ua[i]; 926223637Sbz 927223637Sbz /* check for invalid values */ 928223637Sbz if (up->timeout >= PFTM_MAX || 929223637Sbz up->src.state > PF_TCPS_PROXY_DST || 930223637Sbz up->dst.state > PF_TCPS_PROXY_DST) { 931223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) { 932223637Sbz printf("pfsync_input: " 933223637Sbz "PFSYNC_ACT_UPD_C: " 934223637Sbz "invalid value\n"); 935130613Smlaier } 936223637Sbz V_pfsyncstats.pfsyncs_badval++; 937223637Sbz continue; 938223637Sbz } 939130613Smlaier 940240233Sglebius st = pf_find_state_byid(up->id, up->creatorid); 941223637Sbz if (st == NULL) { 942223637Sbz /* We don't have this state. Ask for it. */ 943240233Sglebius PFSYNC_LOCK(sc); 944240233Sglebius pfsync_request_update(up->creatorid, up->id); 945240233Sglebius PFSYNC_UNLOCK(sc); 946223637Sbz continue; 947223637Sbz } 948223637Sbz 949240233Sglebius if (st->state_flags & PFSTATE_ACK) { 950240233Sglebius PFSYNC_LOCK(sc); 951240233Sglebius pfsync_undefer_state(st, 1); 952240233Sglebius PFSYNC_UNLOCK(sc); 953240233Sglebius } 954223637Sbz 955242694Sglebius if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) 956242694Sglebius sync = pfsync_upd_tcp(st, &up->src, &up->dst); 957223637Sbz else { 958242694Sglebius sync = 0; 959242694Sglebius 960223637Sbz /* 961242694Sglebius * Non-TCP protocol state machine always go 962242694Sglebius * forwards 963223637Sbz */ 964223637Sbz if (st->src.state > up->src.state) 965242694Sglebius sync++; 966242694Sglebius else 967242694Sglebius pf_state_peer_ntoh(&up->src, &st->src); 968242694Sglebius if (st->dst.state > up->dst.state) 969242694Sglebius sync++; 970242694Sglebius else 971242694Sglebius pf_state_peer_ntoh(&up->dst, &st->dst); 972223637Sbz } 973242694Sglebius if (sync < 2) { 974242694Sglebius pfsync_alloc_scrub_memory(&up->dst, &st->dst); 975242694Sglebius pf_state_peer_ntoh(&up->dst, &st->dst); 976242694Sglebius st->expire = time_uptime; 977242694Sglebius st->timeout = up->timeout; 978242694Sglebius } 979242694Sglebius st->pfsync_time = time_uptime; 980223637Sbz 981242694Sglebius if (sync) { 982223637Sbz V_pfsyncstats.pfsyncs_stale++; 983145836Smlaier 984223637Sbz pfsync_update_state(st); 985240233Sglebius PF_STATE_UNLOCK(st); 986240233Sglebius PFSYNC_LOCK(sc); 987240233Sglebius pfsync_push(sc); 988240233Sglebius PFSYNC_UNLOCK(sc); 989223637Sbz continue; 990130613Smlaier } 991240233Sglebius PF_STATE_UNLOCK(st); 992223637Sbz } 993223637Sbz 994223637Sbz return (len); 995223637Sbz} 996223637Sbz 997240233Sglebiusstatic int 998223637Sbzpfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 999223637Sbz{ 1000223637Sbz struct pfsync_upd_req *ur, *ura; 1001223637Sbz struct mbuf *mp; 1002223637Sbz int len = count * sizeof(*ur); 1003223637Sbz int i, offp; 1004223637Sbz 1005223637Sbz struct pf_state *st; 1006223637Sbz 1007223637Sbz mp = m_pulldown(m, offset, len, &offp); 1008223637Sbz if (mp == NULL) { 1009223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1010223637Sbz return (-1); 1011130613Smlaier } 1012223637Sbz ura = (struct pfsync_upd_req *)(mp->m_data + offp); 1013130613Smlaier 1014223637Sbz for (i = 0; i < count; i++) { 1015223637Sbz ur = &ura[i]; 1016130613Smlaier 1017240233Sglebius if (ur->id == 0 && ur->creatorid == 0) 1018223637Sbz pfsync_bulk_start(); 1019223637Sbz else { 1020240233Sglebius st = pf_find_state_byid(ur->id, ur->creatorid); 1021130613Smlaier if (st == NULL) { 1022223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1023130613Smlaier continue; 1024130613Smlaier } 1025240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) { 1026240233Sglebius PF_STATE_UNLOCK(st); 1027223637Sbz continue; 1028240233Sglebius } 1029223637Sbz 1030223637Sbz pfsync_update_state_req(st); 1031240233Sglebius PF_STATE_UNLOCK(st); 1032130613Smlaier } 1033223637Sbz } 1034223637Sbz 1035223637Sbz return (len); 1036223637Sbz} 1037223637Sbz 1038240233Sglebiusstatic int 1039223637Sbzpfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1040223637Sbz{ 1041223637Sbz struct mbuf *mp; 1042223637Sbz struct pfsync_state *sa, *sp; 1043223637Sbz struct pf_state *st; 1044223637Sbz int len = count * sizeof(*sp); 1045223637Sbz int offp, i; 1046223637Sbz 1047223637Sbz mp = m_pulldown(m, offset, len, &offp); 1048223637Sbz if (mp == NULL) { 1049223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1050223637Sbz return (-1); 1051223637Sbz } 1052223637Sbz sa = (struct pfsync_state *)(mp->m_data + offp); 1053223637Sbz 1054223637Sbz for (i = 0; i < count; i++) { 1055223637Sbz sp = &sa[i]; 1056223637Sbz 1057240233Sglebius st = pf_find_state_byid(sp->id, sp->creatorid); 1058223637Sbz if (st == NULL) { 1059223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1060223637Sbz continue; 1061130613Smlaier } 1062240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 1063240233Sglebius pf_unlink_state(st, PF_ENTER_LOCKED); 1064223637Sbz } 1065130613Smlaier 1066223637Sbz return (len); 1067223637Sbz} 1068223637Sbz 1069240233Sglebiusstatic int 1070223637Sbzpfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1071223637Sbz{ 1072223637Sbz struct mbuf *mp; 1073223637Sbz struct pfsync_del_c *sa, *sp; 1074223637Sbz struct pf_state *st; 1075223637Sbz int len = count * sizeof(*sp); 1076223637Sbz int offp, i; 1077223637Sbz 1078223637Sbz mp = m_pulldown(m, offset, len, &offp); 1079223637Sbz if (mp == NULL) { 1080223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1081223637Sbz return (-1); 1082223637Sbz } 1083223637Sbz sa = (struct pfsync_del_c *)(mp->m_data + offp); 1084223637Sbz 1085223637Sbz for (i = 0; i < count; i++) { 1086223637Sbz sp = &sa[i]; 1087130613Smlaier 1088240233Sglebius st = pf_find_state_byid(sp->id, sp->creatorid); 1089223637Sbz if (st == NULL) { 1090223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1091223637Sbz continue; 1092223637Sbz } 1093223637Sbz 1094240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 1095240233Sglebius pf_unlink_state(st, PF_ENTER_LOCKED); 1096223637Sbz } 1097223637Sbz 1098223637Sbz return (len); 1099223637Sbz} 1100223637Sbz 1101240233Sglebiusstatic int 1102223637Sbzpfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1103223637Sbz{ 1104223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1105223637Sbz struct pfsync_bus *bus; 1106223637Sbz struct mbuf *mp; 1107223637Sbz int len = count * sizeof(*bus); 1108223637Sbz int offp; 1109223637Sbz 1110240233Sglebius PFSYNC_BLOCK(sc); 1111240233Sglebius 1112223637Sbz /* If we're not waiting for a bulk update, who cares. */ 1113240233Sglebius if (sc->sc_ureq_sent == 0) { 1114240233Sglebius PFSYNC_BUNLOCK(sc); 1115223637Sbz return (len); 1116240233Sglebius } 1117223637Sbz 1118223637Sbz mp = m_pulldown(m, offset, len, &offp); 1119223637Sbz if (mp == NULL) { 1120240233Sglebius PFSYNC_BUNLOCK(sc); 1121223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1122223637Sbz return (-1); 1123223637Sbz } 1124223637Sbz bus = (struct pfsync_bus *)(mp->m_data + offp); 1125223637Sbz 1126223637Sbz switch (bus->status) { 1127223637Sbz case PFSYNC_BUS_START: 1128228814Sglebius callout_reset(&sc->sc_bulkfail_tmo, 4 * hz + 1129240233Sglebius V_pf_limits[PF_LIMIT_STATES].limit / 1130229777Sglebius ((sc->sc_ifp->if_mtu - PFSYNC_MINPKT) / 1131228814Sglebius sizeof(struct pfsync_state)), 1132240233Sglebius pfsync_bulk_fail, sc); 1133223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1134223637Sbz printf("pfsync: received bulk update start\n"); 1135130613Smlaier break; 1136130613Smlaier 1137223637Sbz case PFSYNC_BUS_END: 1138223637Sbz if (time_uptime - ntohl(bus->endtime) >= 1139223637Sbz sc->sc_ureq_sent) { 1140223637Sbz /* that's it, we're happy */ 1141223637Sbz sc->sc_ureq_sent = 0; 1142223637Sbz sc->sc_bulk_tries = 0; 1143240233Sglebius callout_stop(&sc->sc_bulkfail_tmo); 1144240233Sglebius if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 1145228736Sglebius (*carp_demote_adj_p)(-V_pfsync_carp_adj, 1146228736Sglebius "pfsync bulk done"); 1147240233Sglebius sc->sc_flags |= PFSYNCF_OK; 1148223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1149223637Sbz printf("pfsync: received valid " 1150223637Sbz "bulk update end\n"); 1151223637Sbz } else { 1152223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1153223637Sbz printf("pfsync: received invalid " 1154223637Sbz "bulk update end: bad timestamp\n"); 1155130613Smlaier } 1156130613Smlaier break; 1157223637Sbz } 1158240233Sglebius PFSYNC_BUNLOCK(sc); 1159223637Sbz 1160223637Sbz return (len); 1161223637Sbz} 1162223637Sbz 1163240233Sglebiusstatic int 1164223637Sbzpfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1165223637Sbz{ 1166223637Sbz int len = count * sizeof(struct pfsync_tdb); 1167223637Sbz 1168223637Sbz#if defined(IPSEC) 1169223637Sbz struct pfsync_tdb *tp; 1170223637Sbz struct mbuf *mp; 1171223637Sbz int offp; 1172223637Sbz int i; 1173223637Sbz int s; 1174223637Sbz 1175223637Sbz mp = m_pulldown(m, offset, len, &offp); 1176223637Sbz if (mp == NULL) { 1177223637Sbz V_pfsyncstats.pfsyncs_badlen++; 1178223637Sbz return (-1); 1179223637Sbz } 1180223637Sbz tp = (struct pfsync_tdb *)(mp->m_data + offp); 1181223637Sbz 1182223637Sbz for (i = 0; i < count; i++) 1183223637Sbz pfsync_update_net_tdb(&tp[i]); 1184171168Smlaier#endif 1185223637Sbz 1186223637Sbz return (len); 1187223637Sbz} 1188223637Sbz 1189223637Sbz#if defined(IPSEC) 1190223637Sbz/* Update an in-kernel tdb. Silently fail if no tdb is found. */ 1191240233Sglebiusstatic void 1192223637Sbzpfsync_update_net_tdb(struct pfsync_tdb *pt) 1193223637Sbz{ 1194223637Sbz struct tdb *tdb; 1195223637Sbz int s; 1196223637Sbz 1197223637Sbz /* check for invalid values */ 1198223637Sbz if (ntohl(pt->spi) <= SPI_RESERVED_MAX || 1199223637Sbz (pt->dst.sa.sa_family != AF_INET && 1200240233Sglebius pt->dst.sa.sa_family != AF_INET6)) 1201223637Sbz goto bad; 1202223637Sbz 1203223637Sbz tdb = gettdb(pt->spi, &pt->dst, pt->sproto); 1204223637Sbz if (tdb) { 1205223637Sbz pt->rpl = ntohl(pt->rpl); 1206240233Sglebius pt->cur_bytes = (unsigned long long)be64toh(pt->cur_bytes); 1207223637Sbz 1208223637Sbz /* Neither replay nor byte counter should ever decrease. */ 1209223637Sbz if (pt->rpl < tdb->tdb_rpl || 1210223637Sbz pt->cur_bytes < tdb->tdb_cur_bytes) { 1211223637Sbz goto bad; 1212223637Sbz } 1213223637Sbz 1214223637Sbz tdb->tdb_rpl = pt->rpl; 1215223637Sbz tdb->tdb_cur_bytes = pt->cur_bytes; 1216130613Smlaier } 1217223637Sbz return; 1218130613Smlaier 1219223637Sbzbad: 1220223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 1221223637Sbz printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " 1222223637Sbz "invalid value\n"); 1223223637Sbz V_pfsyncstats.pfsyncs_badstate++; 1224223637Sbz return; 1225130613Smlaier} 1226223637Sbz#endif 1227130613Smlaier 1228223637Sbz 1229240233Sglebiusstatic int 1230223637Sbzpfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1231223637Sbz{ 1232223637Sbz /* check if we are at the right place in the packet */ 1233244185Sglebius if (offset != m->m_pkthdr.len) 1234244185Sglebius V_pfsyncstats.pfsyncs_badlen++; 1235223637Sbz 1236223637Sbz /* we're done. free and let the caller return */ 1237223637Sbz m_freem(m); 1238223637Sbz return (-1); 1239223637Sbz} 1240223637Sbz 1241240233Sglebiusstatic int 1242223637Sbzpfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) 1243223637Sbz{ 1244223637Sbz V_pfsyncstats.pfsyncs_badact++; 1245223637Sbz 1246223637Sbz m_freem(m); 1247223637Sbz return (-1); 1248223637Sbz} 1249223637Sbz 1250240233Sglebiusstatic int 1251249925Sglebiuspfsyncoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 1252223637Sbz struct route *rt) 1253126258Smlaier{ 1254126258Smlaier m_freem(m); 1255126258Smlaier return (0); 1256126258Smlaier} 1257126258Smlaier 1258126258Smlaier/* ARGSUSED */ 1259240233Sglebiusstatic int 1260126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1261126258Smlaier{ 1262126258Smlaier struct pfsync_softc *sc = ifp->if_softc; 1263126258Smlaier struct ifreq *ifr = (struct ifreq *)data; 1264130613Smlaier struct pfsyncreq pfsyncr; 1265240233Sglebius int error; 1266126258Smlaier 1267126258Smlaier switch (cmd) { 1268126258Smlaier case SIOCSIFFLAGS: 1269240233Sglebius PFSYNC_LOCK(sc); 1270241057Sglebius if (ifp->if_flags & IFF_UP) { 1271148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1272241057Sglebius PFSYNC_UNLOCK(sc); 1273241057Sglebius pfsync_pointers_init(); 1274241057Sglebius } else { 1275148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1276241057Sglebius PFSYNC_UNLOCK(sc); 1277241057Sglebius pfsync_pointers_uninit(); 1278241057Sglebius } 1279126258Smlaier break; 1280126258Smlaier case SIOCSIFMTU: 1281229777Sglebius if (!sc->sc_sync_if || 1282229777Sglebius ifr->ifr_mtu <= PFSYNC_MINPKT || 1283229777Sglebius ifr->ifr_mtu > sc->sc_sync_if->if_mtu) 1284126258Smlaier return (EINVAL); 1285223637Sbz if (ifr->ifr_mtu < ifp->if_mtu) { 1286240233Sglebius PFSYNC_LOCK(sc); 1287240233Sglebius if (sc->sc_len > PFSYNC_MINPKT) 1288240233Sglebius pfsync_sendout(1); 1289240233Sglebius PFSYNC_UNLOCK(sc); 1290223637Sbz } 1291223637Sbz ifp->if_mtu = ifr->ifr_mtu; 1292126258Smlaier break; 1293130613Smlaier case SIOCGETPFSYNC: 1294130613Smlaier bzero(&pfsyncr, sizeof(pfsyncr)); 1295240233Sglebius PFSYNC_LOCK(sc); 1296223637Sbz if (sc->sc_sync_if) { 1297145836Smlaier strlcpy(pfsyncr.pfsyncr_syncdev, 1298223637Sbz sc->sc_sync_if->if_xname, IFNAMSIZ); 1299223637Sbz } 1300145836Smlaier pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; 1301130613Smlaier pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; 1302240233Sglebius pfsyncr.pfsyncr_defer = (PFSYNCF_DEFER == 1303240233Sglebius (sc->sc_flags & PFSYNCF_DEFER)); 1304240233Sglebius PFSYNC_UNLOCK(sc); 1305223637Sbz return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))); 1306223637Sbz 1307130613Smlaier case SIOCSETPFSYNC: 1308240233Sglebius { 1309240233Sglebius struct ip_moptions *imo = &sc->sc_imo; 1310240233Sglebius struct ifnet *sifp; 1311240233Sglebius struct ip *ip; 1312240233Sglebius void *mship = NULL; 1313240233Sglebius 1314164033Srwatson if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) 1315130613Smlaier return (error); 1316130613Smlaier if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr)))) 1317130613Smlaier return (error); 1318130613Smlaier 1319240233Sglebius if (pfsyncr.pfsyncr_maxupdates > 255) 1320240233Sglebius return (EINVAL); 1321240233Sglebius 1322240233Sglebius if (pfsyncr.pfsyncr_syncdev[0] == 0) 1323240233Sglebius sifp = NULL; 1324240233Sglebius else if ((sifp = ifunit_ref(pfsyncr.pfsyncr_syncdev)) == NULL) 1325240233Sglebius return (EINVAL); 1326240233Sglebius 1327253769Sae if (sifp != NULL && ( 1328253769Sae pfsyncr.pfsyncr_syncpeer.s_addr == 0 || 1329253769Sae pfsyncr.pfsyncr_syncpeer.s_addr == 1330253769Sae htonl(INADDR_PFSYNC_GROUP))) 1331240233Sglebius mship = malloc((sizeof(struct in_multi *) * 1332240233Sglebius IP_MIN_MEMBERSHIPS), M_PFSYNC, M_WAITOK | M_ZERO); 1333240233Sglebius 1334240233Sglebius PFSYNC_LOCK(sc); 1335145836Smlaier if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) 1336159603Smlaier sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); 1337145836Smlaier else 1338145836Smlaier sc->sc_sync_peer.s_addr = 1339145836Smlaier pfsyncr.pfsyncr_syncpeer.s_addr; 1340145836Smlaier 1341240233Sglebius sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; 1342240233Sglebius if (pfsyncr.pfsyncr_defer) { 1343240233Sglebius sc->sc_flags |= PFSYNCF_DEFER; 1344240233Sglebius pfsync_defer_ptr = pfsync_defer; 1345240233Sglebius } else { 1346240233Sglebius sc->sc_flags &= ~PFSYNCF_DEFER; 1347240233Sglebius pfsync_defer_ptr = NULL; 1348171168Smlaier } 1349130613Smlaier 1350240233Sglebius if (sifp == NULL) { 1351240233Sglebius if (sc->sc_sync_if) 1352240233Sglebius if_rele(sc->sc_sync_if); 1353223637Sbz sc->sc_sync_if = NULL; 1354229850Sglebius if (imo->imo_membership) 1355229850Sglebius pfsync_multicast_cleanup(sc); 1356240233Sglebius PFSYNC_UNLOCK(sc); 1357130613Smlaier break; 1358130613Smlaier } 1359145836Smlaier 1360240233Sglebius if (sc->sc_len > PFSYNC_MINPKT && 1361240233Sglebius (sifp->if_mtu < sc->sc_ifp->if_mtu || 1362223637Sbz (sc->sc_sync_if != NULL && 1363223637Sbz sifp->if_mtu < sc->sc_sync_if->if_mtu) || 1364240233Sglebius sifp->if_mtu < MCLBYTES - sizeof(struct ip))) 1365240233Sglebius pfsync_sendout(1); 1366130613Smlaier 1367240233Sglebius if (imo->imo_membership) 1368229850Sglebius pfsync_multicast_cleanup(sc); 1369130613Smlaier 1370240233Sglebius if (sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { 1371240233Sglebius error = pfsync_multicast_setup(sc, sifp, mship); 1372240233Sglebius if (error) { 1373240233Sglebius if_rele(sifp); 1374240233Sglebius free(mship, M_PFSYNC); 1375229850Sglebius return (error); 1376145836Smlaier } 1377145836Smlaier } 1378240233Sglebius if (sc->sc_sync_if) 1379240233Sglebius if_rele(sc->sc_sync_if); 1380240233Sglebius sc->sc_sync_if = sifp; 1381130613Smlaier 1382223637Sbz ip = &sc->sc_template; 1383223637Sbz bzero(ip, sizeof(*ip)); 1384223637Sbz ip->ip_v = IPVERSION; 1385223637Sbz ip->ip_hl = sizeof(sc->sc_template) >> 2; 1386223637Sbz ip->ip_tos = IPTOS_LOWDELAY; 1387240233Sglebius /* len and id are set later. */ 1388241913Sglebius ip->ip_off = htons(IP_DF); 1389223637Sbz ip->ip_ttl = PFSYNC_DFLTTL; 1390223637Sbz ip->ip_p = IPPROTO_PFSYNC; 1391223637Sbz ip->ip_src.s_addr = INADDR_ANY; 1392223637Sbz ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr; 1393223637Sbz 1394240233Sglebius /* Request a full state table update. */ 1395240233Sglebius if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 1396240233Sglebius (*carp_demote_adj_p)(V_pfsync_carp_adj, 1397240233Sglebius "pfsync bulk start"); 1398240233Sglebius sc->sc_flags &= ~PFSYNCF_OK; 1399240233Sglebius if (V_pf_status.debug >= PF_DEBUG_MISC) 1400240233Sglebius printf("pfsync: requesting bulk update\n"); 1401240233Sglebius pfsync_request_update(0, 0); 1402240233Sglebius PFSYNC_UNLOCK(sc); 1403240233Sglebius PFSYNC_BLOCK(sc); 1404240233Sglebius sc->sc_ureq_sent = time_uptime; 1405240233Sglebius callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail, 1406240233Sglebius sc); 1407240233Sglebius PFSYNC_BUNLOCK(sc); 1408130613Smlaier 1409130613Smlaier break; 1410240233Sglebius } 1411126258Smlaier default: 1412126258Smlaier return (ENOTTY); 1413126258Smlaier } 1414126258Smlaier 1415126258Smlaier return (0); 1416126258Smlaier} 1417126258Smlaier 1418241056Sglebiusstatic void 1419241056Sglebiuspfsync_out_state(struct pf_state *st, void *buf) 1420130613Smlaier{ 1421241056Sglebius struct pfsync_state *sp = buf; 1422130613Smlaier 1423223637Sbz pfsync_state_export(sp, st); 1424223637Sbz} 1425223637Sbz 1426241056Sglebiusstatic void 1427241056Sglebiuspfsync_out_iack(struct pf_state *st, void *buf) 1428223637Sbz{ 1429241056Sglebius struct pfsync_ins_ack *iack = buf; 1430223637Sbz 1431223637Sbz iack->id = st->id; 1432223637Sbz iack->creatorid = st->creatorid; 1433223637Sbz} 1434223637Sbz 1435241056Sglebiusstatic void 1436241056Sglebiuspfsync_out_upd_c(struct pf_state *st, void *buf) 1437223637Sbz{ 1438241056Sglebius struct pfsync_upd_c *up = buf; 1439223637Sbz 1440232685Sglebius bzero(up, sizeof(*up)); 1441223637Sbz up->id = st->id; 1442223637Sbz pf_state_peer_hton(&st->src, &up->src); 1443223637Sbz pf_state_peer_hton(&st->dst, &up->dst); 1444223637Sbz up->creatorid = st->creatorid; 1445223637Sbz up->timeout = st->timeout; 1446223637Sbz} 1447223637Sbz 1448241056Sglebiusstatic void 1449241056Sglebiuspfsync_out_del(struct pf_state *st, void *buf) 1450223637Sbz{ 1451241056Sglebius struct pfsync_del_c *dp = buf; 1452223637Sbz 1453223637Sbz dp->id = st->id; 1454223637Sbz dp->creatorid = st->creatorid; 1455240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 1456223637Sbz} 1457223637Sbz 1458240233Sglebiusstatic void 1459223637Sbzpfsync_drop(struct pfsync_softc *sc) 1460223637Sbz{ 1461240233Sglebius struct pf_state *st, *next; 1462223637Sbz struct pfsync_upd_req_item *ur; 1463223637Sbz int q; 1464223637Sbz 1465223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 1466223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 1467223637Sbz continue; 1468223637Sbz 1469240233Sglebius TAILQ_FOREACH_SAFE(st, &sc->sc_qs[q], sync_list, next) { 1470223637Sbz KASSERT(st->sync_state == q, 1471229964Sglebius ("%s: st->sync_state == q", 1472240233Sglebius __func__)); 1473223637Sbz st->sync_state = PFSYNC_S_NONE; 1474240233Sglebius pf_release_state(st); 1475223637Sbz } 1476223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 1477223637Sbz } 1478223637Sbz 1479223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 1480223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 1481240233Sglebius free(ur, M_PFSYNC); 1482223637Sbz } 1483223637Sbz 1484223637Sbz sc->sc_plus = NULL; 1485223637Sbz sc->sc_len = PFSYNC_MINPKT; 1486126258Smlaier} 1487126258Smlaier 1488229976Sglebiusstatic void 1489240233Sglebiuspfsync_sendout(int schedswi) 1490229976Sglebius{ 1491229976Sglebius struct pfsync_softc *sc = V_pfsyncif; 1492223637Sbz struct ifnet *ifp = sc->sc_ifp; 1493126258Smlaier struct mbuf *m; 1494223637Sbz struct ip *ip; 1495223637Sbz struct pfsync_header *ph; 1496223637Sbz struct pfsync_subheader *subh; 1497241056Sglebius struct pf_state *st; 1498223637Sbz struct pfsync_upd_req_item *ur; 1499223637Sbz int offset; 1500223637Sbz int q, count = 0; 1501126258Smlaier 1502240233Sglebius KASSERT(sc != NULL, ("%s: null sc", __func__)); 1503240233Sglebius KASSERT(sc->sc_len > PFSYNC_MINPKT, 1504240233Sglebius ("%s: sc_len %zu", __func__, sc->sc_len)); 1505240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1506223637Sbz 1507223637Sbz if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) { 1508223637Sbz pfsync_drop(sc); 1509223637Sbz return; 1510223637Sbz } 1511223637Sbz 1512248207Sglebius m = m_get2(max_linkhdr + sc->sc_len, M_NOWAIT, MT_DATA, M_PKTHDR); 1513126258Smlaier if (m == NULL) { 1514171168Smlaier sc->sc_ifp->if_oerrors++; 1515230265Sglebius V_pfsyncstats.pfsyncs_onomem++; 1516230265Sglebius return; 1517230265Sglebius } 1518223637Sbz m->m_data += max_linkhdr; 1519223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 1520130613Smlaier 1521223637Sbz /* build the ip header */ 1522223637Sbz ip = (struct ip *)m->m_data; 1523223637Sbz bcopy(&sc->sc_template, ip, sizeof(*ip)); 1524223637Sbz offset = sizeof(*ip); 1525126258Smlaier 1526241913Sglebius ip->ip_len = htons(m->m_pkthdr.len); 1527223637Sbz ip->ip_id = htons(ip_randomid()); 1528126258Smlaier 1529223637Sbz /* build the pfsync header */ 1530223637Sbz ph = (struct pfsync_header *)(m->m_data + offset); 1531223637Sbz bzero(ph, sizeof(*ph)); 1532223637Sbz offset += sizeof(*ph); 1533126258Smlaier 1534223637Sbz ph->version = PFSYNC_VERSION; 1535223637Sbz ph->len = htons(sc->sc_len - sizeof(*ip)); 1536223637Sbz bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); 1537171168Smlaier 1538223637Sbz /* walk the queues */ 1539223637Sbz for (q = 0; q < PFSYNC_S_COUNT; q++) { 1540223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 1541223637Sbz continue; 1542223637Sbz 1543223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 1544223637Sbz offset += sizeof(*subh); 1545223637Sbz 1546223637Sbz count = 0; 1547241056Sglebius TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { 1548223637Sbz KASSERT(st->sync_state == q, 1549223637Sbz ("%s: st->sync_state == q", 1550240233Sglebius __func__)); 1551240233Sglebius /* 1552240233Sglebius * XXXGL: some of write methods do unlocked reads 1553240233Sglebius * of state data :( 1554240233Sglebius */ 1555241056Sglebius pfsync_qs[q].write(st, m->m_data + offset); 1556241056Sglebius offset += pfsync_qs[q].len; 1557223637Sbz st->sync_state = PFSYNC_S_NONE; 1558240233Sglebius pf_release_state(st); 1559223637Sbz count++; 1560126258Smlaier } 1561223637Sbz TAILQ_INIT(&sc->sc_qs[q]); 1562130613Smlaier 1563223637Sbz bzero(subh, sizeof(*subh)); 1564223637Sbz subh->action = pfsync_qs[q].action; 1565223637Sbz subh->count = htons(count); 1566240233Sglebius V_pfsyncstats.pfsyncs_oacts[pfsync_qs[q].action] += count; 1567126258Smlaier } 1568126258Smlaier 1569223637Sbz if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) { 1570223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 1571223637Sbz offset += sizeof(*subh); 1572126258Smlaier 1573223637Sbz count = 0; 1574223637Sbz while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { 1575223637Sbz TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); 1576130613Smlaier 1577223637Sbz bcopy(&ur->ur_msg, m->m_data + offset, 1578223637Sbz sizeof(ur->ur_msg)); 1579223637Sbz offset += sizeof(ur->ur_msg); 1580240233Sglebius free(ur, M_PFSYNC); 1581223637Sbz count++; 1582223637Sbz } 1583130613Smlaier 1584223637Sbz bzero(subh, sizeof(*subh)); 1585223637Sbz subh->action = PFSYNC_ACT_UPD_REQ; 1586223637Sbz subh->count = htons(count); 1587240233Sglebius V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_UPD_REQ] += count; 1588223637Sbz } 1589130613Smlaier 1590223637Sbz /* has someone built a custom region for us to add? */ 1591223637Sbz if (sc->sc_plus != NULL) { 1592223637Sbz bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen); 1593223637Sbz offset += sc->sc_pluslen; 1594130613Smlaier 1595223637Sbz sc->sc_plus = NULL; 1596130613Smlaier } 1597130613Smlaier 1598223637Sbz subh = (struct pfsync_subheader *)(m->m_data + offset); 1599223637Sbz offset += sizeof(*subh); 1600130613Smlaier 1601223637Sbz bzero(subh, sizeof(*subh)); 1602223637Sbz subh->action = PFSYNC_ACT_EOF; 1603223637Sbz subh->count = htons(1); 1604240233Sglebius V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_EOF]++; 1605130613Smlaier 1606223637Sbz /* we're done, let's put it on the wire */ 1607223637Sbz if (ifp->if_bpf) { 1608223637Sbz m->m_data += sizeof(*ip); 1609223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip); 1610223637Sbz BPF_MTAP(ifp, m); 1611223637Sbz m->m_data -= sizeof(*ip); 1612223637Sbz m->m_len = m->m_pkthdr.len = sc->sc_len; 1613130613Smlaier } 1614130613Smlaier 1615223637Sbz if (sc->sc_sync_if == NULL) { 1616223637Sbz sc->sc_len = PFSYNC_MINPKT; 1617223637Sbz m_freem(m); 1618223637Sbz return; 1619223637Sbz } 1620126258Smlaier 1621223637Sbz sc->sc_ifp->if_opackets++; 1622223637Sbz sc->sc_ifp->if_obytes += m->m_pkthdr.len; 1623226660Sglebius sc->sc_len = PFSYNC_MINPKT; 1624226660Sglebius 1625229976Sglebius if (!_IF_QFULL(&sc->sc_ifp->if_snd)) 1626229976Sglebius _IF_ENQUEUE(&sc->sc_ifp->if_snd, m); 1627229976Sglebius else { 1628229976Sglebius m_freem(m); 1629240233Sglebius sc->sc_ifp->if_snd.ifq_drops++; 1630229976Sglebius } 1631229976Sglebius if (schedswi) 1632229976Sglebius swi_sched(V_pfsync_swi_cookie, 0); 1633126258Smlaier} 1634126258Smlaier 1635240233Sglebiusstatic void 1636223637Sbzpfsync_insert_state(struct pf_state *st) 1637126258Smlaier{ 1638223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1639130613Smlaier 1640240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) 1641240233Sglebius return; 1642130613Smlaier 1643240233Sglebius if ((st->rule.ptr->rule_flag & PFRULE_NOSYNC) || 1644223637Sbz st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) { 1645240233Sglebius st->state_flags |= PFSTATE_NOSYNC; 1646223637Sbz return; 1647130613Smlaier } 1648130613Smlaier 1649223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 1650250313Sglebius ("%s: st->sync_state %u", __func__, st->sync_state)); 1651223637Sbz 1652240233Sglebius PFSYNC_LOCK(sc); 1653223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 1654240233Sglebius callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif); 1655223637Sbz 1656223637Sbz pfsync_q_ins(st, PFSYNC_S_INS); 1657240233Sglebius PFSYNC_UNLOCK(sc); 1658223637Sbz 1659233846Sglebius st->sync_updates = 0; 1660130613Smlaier} 1661130613Smlaier 1662240233Sglebiusstatic int 1663223637Sbzpfsync_defer(struct pf_state *st, struct mbuf *m) 1664130613Smlaier{ 1665223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1666223637Sbz struct pfsync_deferral *pd; 1667126258Smlaier 1668240233Sglebius if (m->m_flags & (M_BCAST|M_MCAST)) 1669240233Sglebius return (0); 1670223637Sbz 1671240233Sglebius PFSYNC_LOCK(sc); 1672240233Sglebius 1673240233Sglebius if (sc == NULL || !(sc->sc_ifp->if_flags & IFF_DRV_RUNNING) || 1674240233Sglebius !(sc->sc_flags & PFSYNCF_DEFER)) { 1675240233Sglebius PFSYNC_UNLOCK(sc); 1676233846Sglebius return (0); 1677240233Sglebius } 1678233846Sglebius 1679240233Sglebius if (sc->sc_deferred >= 128) 1680223637Sbz pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); 1681223637Sbz 1682240233Sglebius pd = malloc(sizeof(*pd), M_PFSYNC, M_NOWAIT); 1683223637Sbz if (pd == NULL) 1684171168Smlaier return (0); 1685223637Sbz sc->sc_deferred++; 1686171168Smlaier 1687223637Sbz m->m_flags |= M_SKIP_FIREWALL; 1688240233Sglebius st->state_flags |= PFSTATE_ACK; 1689223637Sbz 1690240233Sglebius pd->pd_sc = sc; 1691240233Sglebius pd->pd_refs = 0; 1692223637Sbz pd->pd_st = st; 1693240233Sglebius pf_ref_state(st); 1694223637Sbz pd->pd_m = m; 1695223637Sbz 1696223637Sbz TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry); 1697240233Sglebius callout_init_mtx(&pd->pd_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED); 1698240233Sglebius callout_reset(&pd->pd_tmo, 10, pfsync_defer_tmo, pd); 1699126258Smlaier 1700240233Sglebius pfsync_push(sc); 1701233846Sglebius 1702223637Sbz return (1); 1703126258Smlaier} 1704126258Smlaier 1705240233Sglebiusstatic void 1706223637Sbzpfsync_undefer(struct pfsync_deferral *pd, int drop) 1707126258Smlaier{ 1708240233Sglebius struct pfsync_softc *sc = pd->pd_sc; 1709240233Sglebius struct mbuf *m = pd->pd_m; 1710240233Sglebius struct pf_state *st = pd->pd_st; 1711126258Smlaier 1712240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1713223637Sbz 1714223637Sbz TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 1715223637Sbz sc->sc_deferred--; 1716240233Sglebius pd->pd_st->state_flags &= ~PFSTATE_ACK; /* XXX: locking! */ 1717240233Sglebius free(pd, M_PFSYNC); 1718240233Sglebius pf_release_state(st); 1719223637Sbz 1720223637Sbz if (drop) 1721240233Sglebius m_freem(m); 1722223637Sbz else { 1723240233Sglebius _IF_ENQUEUE(&sc->sc_ifp->if_snd, m); 1724240233Sglebius pfsync_push(sc); 1725223637Sbz } 1726126258Smlaier} 1727126258Smlaier 1728240233Sglebiusstatic void 1729223637Sbzpfsync_defer_tmo(void *arg) 1730171168Smlaier{ 1731223637Sbz struct pfsync_deferral *pd = arg; 1732240233Sglebius struct pfsync_softc *sc = pd->pd_sc; 1733240233Sglebius struct mbuf *m = pd->pd_m; 1734240233Sglebius struct pf_state *st = pd->pd_st; 1735171168Smlaier 1736240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1737240233Sglebius 1738240233Sglebius CURVNET_SET(m->m_pkthdr.rcvif->if_vnet); 1739240233Sglebius 1740240233Sglebius TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); 1741240233Sglebius sc->sc_deferred--; 1742240233Sglebius pd->pd_st->state_flags &= ~PFSTATE_ACK; /* XXX: locking! */ 1743240233Sglebius if (pd->pd_refs == 0) 1744240233Sglebius free(pd, M_PFSYNC); 1745240233Sglebius PFSYNC_UNLOCK(sc); 1746240233Sglebius 1747240233Sglebius ip_output(m, NULL, NULL, 0, NULL, NULL); 1748240233Sglebius 1749240233Sglebius pf_release_state(st); 1750240233Sglebius 1751223637Sbz CURVNET_RESTORE(); 1752171168Smlaier} 1753223637Sbz 1754240233Sglebiusstatic void 1755240233Sglebiuspfsync_undefer_state(struct pf_state *st, int drop) 1756223637Sbz{ 1757223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1758223637Sbz struct pfsync_deferral *pd; 1759171168Smlaier 1760240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1761240233Sglebius 1762223637Sbz TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) { 1763223637Sbz if (pd->pd_st == st) { 1764240233Sglebius if (callout_stop(&pd->pd_tmo)) 1765240233Sglebius pfsync_undefer(pd, drop); 1766223637Sbz return; 1767223637Sbz } 1768223637Sbz } 1769223637Sbz 1770240233Sglebius panic("%s: unable to find deferred state", __func__); 1771223637Sbz} 1772223637Sbz 1773240233Sglebiusstatic void 1774223637Sbzpfsync_update_state(struct pf_state *st) 1775130613Smlaier{ 1776223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1777223637Sbz int sync = 0; 1778130613Smlaier 1779240233Sglebius PF_STATE_LOCK_ASSERT(st); 1780240233Sglebius PFSYNC_LOCK(sc); 1781130613Smlaier 1782240233Sglebius if (st->state_flags & PFSTATE_ACK) 1783240233Sglebius pfsync_undefer_state(st, 0); 1784240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) { 1785223637Sbz if (st->sync_state != PFSYNC_S_NONE) 1786223637Sbz pfsync_q_del(st); 1787240233Sglebius PFSYNC_UNLOCK(sc); 1788223637Sbz return; 1789130613Smlaier } 1790223637Sbz 1791223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 1792240233Sglebius callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif); 1793223637Sbz 1794223637Sbz switch (st->sync_state) { 1795223637Sbz case PFSYNC_S_UPD_C: 1796223637Sbz case PFSYNC_S_UPD: 1797223637Sbz case PFSYNC_S_INS: 1798223637Sbz /* we're already handling it */ 1799223637Sbz 1800228816Sglebius if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) { 1801228816Sglebius st->sync_updates++; 1802228816Sglebius if (st->sync_updates >= sc->sc_maxupdates) 1803228816Sglebius sync = 1; 1804228816Sglebius } 1805223637Sbz break; 1806223637Sbz 1807223637Sbz case PFSYNC_S_IACK: 1808223637Sbz pfsync_q_del(st); 1809223637Sbz case PFSYNC_S_NONE: 1810223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD_C); 1811223637Sbz st->sync_updates = 0; 1812223637Sbz break; 1813223637Sbz 1814223637Sbz default: 1815240233Sglebius panic("%s: unexpected sync state %d", __func__, st->sync_state); 1816223637Sbz } 1817223637Sbz 1818240233Sglebius if (sync || (time_uptime - st->pfsync_time) < 2) 1819240233Sglebius pfsync_push(sc); 1820240233Sglebius 1821240233Sglebius PFSYNC_UNLOCK(sc); 1822130613Smlaier} 1823130613Smlaier 1824240233Sglebiusstatic void 1825223637Sbzpfsync_request_update(u_int32_t creatorid, u_int64_t id) 1826130613Smlaier{ 1827223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1828223637Sbz struct pfsync_upd_req_item *item; 1829223637Sbz size_t nlen = sizeof(struct pfsync_upd_req); 1830130613Smlaier 1831240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1832226544Sbz 1833130613Smlaier /* 1834241131Sglebius * This code does a bit to prevent multiple update requests for the 1835241131Sglebius * same state being generated. It searches current subheader queue, 1836241131Sglebius * but it doesn't lookup into queue of already packed datagrams. 1837130613Smlaier */ 1838241131Sglebius TAILQ_FOREACH(item, &sc->sc_upd_req_list, ur_entry) 1839241131Sglebius if (item->ur_msg.id == id && 1840241131Sglebius item->ur_msg.creatorid == creatorid) 1841241131Sglebius return; 1842241131Sglebius 1843240233Sglebius item = malloc(sizeof(*item), M_PFSYNC, M_NOWAIT); 1844240233Sglebius if (item == NULL) 1845240233Sglebius return; /* XXX stats */ 1846130613Smlaier 1847223637Sbz item->ur_msg.id = id; 1848223637Sbz item->ur_msg.creatorid = creatorid; 1849171168Smlaier 1850223637Sbz if (TAILQ_EMPTY(&sc->sc_upd_req_list)) 1851223637Sbz nlen += sizeof(struct pfsync_subheader); 1852223637Sbz 1853229777Sglebius if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 1854240233Sglebius pfsync_sendout(1); 1855223637Sbz 1856223637Sbz nlen = sizeof(struct pfsync_subheader) + 1857223637Sbz sizeof(struct pfsync_upd_req); 1858130613Smlaier } 1859223637Sbz 1860223637Sbz TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry); 1861223637Sbz sc->sc_len += nlen; 1862223637Sbz} 1863223637Sbz 1864240233Sglebiusstatic void 1865223637Sbzpfsync_update_state_req(struct pf_state *st) 1866223637Sbz{ 1867223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1868223637Sbz 1869240233Sglebius PF_STATE_LOCK_ASSERT(st); 1870240233Sglebius PFSYNC_LOCK(sc); 1871226544Sbz 1872240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) { 1873223637Sbz if (st->sync_state != PFSYNC_S_NONE) 1874223637Sbz pfsync_q_del(st); 1875240233Sglebius PFSYNC_UNLOCK(sc); 1876223637Sbz return; 1877223637Sbz } 1878223637Sbz 1879223637Sbz switch (st->sync_state) { 1880223637Sbz case PFSYNC_S_UPD_C: 1881223637Sbz case PFSYNC_S_IACK: 1882223637Sbz pfsync_q_del(st); 1883223637Sbz case PFSYNC_S_NONE: 1884223637Sbz pfsync_q_ins(st, PFSYNC_S_UPD); 1885240233Sglebius pfsync_push(sc); 1886240233Sglebius break; 1887223637Sbz 1888223637Sbz case PFSYNC_S_INS: 1889223637Sbz case PFSYNC_S_UPD: 1890223637Sbz case PFSYNC_S_DEL: 1891223637Sbz /* we're already handling it */ 1892240233Sglebius break; 1893223637Sbz 1894223637Sbz default: 1895240233Sglebius panic("%s: unexpected sync state %d", __func__, st->sync_state); 1896223637Sbz } 1897240233Sglebius 1898240233Sglebius PFSYNC_UNLOCK(sc); 1899130613Smlaier} 1900130613Smlaier 1901240233Sglebiusstatic void 1902223637Sbzpfsync_delete_state(struct pf_state *st) 1903130613Smlaier{ 1904223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1905223637Sbz 1906240233Sglebius PFSYNC_LOCK(sc); 1907240233Sglebius if (st->state_flags & PFSTATE_ACK) 1908240233Sglebius pfsync_undefer_state(st, 1); 1909240233Sglebius if (st->state_flags & PFSTATE_NOSYNC) { 1910223637Sbz if (st->sync_state != PFSYNC_S_NONE) 1911223637Sbz pfsync_q_del(st); 1912240233Sglebius PFSYNC_UNLOCK(sc); 1913223637Sbz return; 1914223637Sbz } 1915223637Sbz 1916223637Sbz if (sc->sc_len == PFSYNC_MINPKT) 1917240233Sglebius callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif); 1918223637Sbz 1919223637Sbz switch (st->sync_state) { 1920223637Sbz case PFSYNC_S_INS: 1921240233Sglebius /* We never got to tell the world so just forget about it. */ 1922223637Sbz pfsync_q_del(st); 1923240233Sglebius break; 1924223637Sbz 1925223637Sbz case PFSYNC_S_UPD_C: 1926223637Sbz case PFSYNC_S_UPD: 1927223637Sbz case PFSYNC_S_IACK: 1928223637Sbz pfsync_q_del(st); 1929223637Sbz /* FALLTHROUGH to putting it on the del list */ 1930223637Sbz 1931223637Sbz case PFSYNC_S_NONE: 1932223637Sbz pfsync_q_ins(st, PFSYNC_S_DEL); 1933240233Sglebius break; 1934223637Sbz 1935223637Sbz default: 1936240233Sglebius panic("%s: unexpected sync state %d", __func__, st->sync_state); 1937130613Smlaier } 1938240233Sglebius PFSYNC_UNLOCK(sc); 1939223637Sbz} 1940223637Sbz 1941240233Sglebiusstatic void 1942223637Sbzpfsync_clear_states(u_int32_t creatorid, const char *ifname) 1943223637Sbz{ 1944240233Sglebius struct pfsync_softc *sc = V_pfsyncif; 1945223637Sbz struct { 1946223637Sbz struct pfsync_subheader subh; 1947223637Sbz struct pfsync_clr clr; 1948223637Sbz } __packed r; 1949223637Sbz 1950223637Sbz bzero(&r, sizeof(r)); 1951223637Sbz 1952223637Sbz r.subh.action = PFSYNC_ACT_CLR; 1953223637Sbz r.subh.count = htons(1); 1954240233Sglebius V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_CLR]++; 1955223637Sbz 1956223637Sbz strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname)); 1957223637Sbz r.clr.creatorid = creatorid; 1958223637Sbz 1959240233Sglebius PFSYNC_LOCK(sc); 1960223637Sbz pfsync_send_plus(&r, sizeof(r)); 1961240233Sglebius PFSYNC_UNLOCK(sc); 1962130613Smlaier} 1963130613Smlaier 1964240233Sglebiusstatic void 1965223637Sbzpfsync_q_ins(struct pf_state *st, int q) 1966126258Smlaier{ 1967223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1968223637Sbz size_t nlen = pfsync_qs[q].len; 1969223637Sbz 1970240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1971226544Sbz 1972223637Sbz KASSERT(st->sync_state == PFSYNC_S_NONE, 1973250313Sglebius ("%s: st->sync_state %u", __func__, st->sync_state)); 1974240233Sglebius KASSERT(sc->sc_len >= PFSYNC_MINPKT, ("pfsync pkt len is too low %zu", 1975240233Sglebius sc->sc_len)); 1976126258Smlaier 1977223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 1978223637Sbz nlen += sizeof(struct pfsync_subheader); 1979130613Smlaier 1980223637Sbz if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { 1981240233Sglebius pfsync_sendout(1); 1982126258Smlaier 1983223637Sbz nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len; 1984130613Smlaier } 1985126258Smlaier 1986223637Sbz sc->sc_len += nlen; 1987223637Sbz TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list); 1988223637Sbz st->sync_state = q; 1989240233Sglebius pf_ref_state(st); 1990171168Smlaier} 1991171168Smlaier 1992240233Sglebiusstatic void 1993223637Sbzpfsync_q_del(struct pf_state *st) 1994171168Smlaier{ 1995223637Sbz struct pfsync_softc *sc = V_pfsyncif; 1996223637Sbz int q = st->sync_state; 1997171168Smlaier 1998240233Sglebius PFSYNC_LOCK_ASSERT(sc); 1999229964Sglebius KASSERT(st->sync_state != PFSYNC_S_NONE, 2000240233Sglebius ("%s: st->sync_state != PFSYNC_S_NONE", __func__)); 2001171168Smlaier 2002223637Sbz sc->sc_len -= pfsync_qs[q].len; 2003223637Sbz TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list); 2004223637Sbz st->sync_state = PFSYNC_S_NONE; 2005240233Sglebius pf_release_state(st); 2006171168Smlaier 2007223637Sbz if (TAILQ_EMPTY(&sc->sc_qs[q])) 2008223637Sbz sc->sc_len -= sizeof(struct pfsync_subheader); 2009223637Sbz} 2010223637Sbz 2011240233Sglebiusstatic void 2012223637Sbzpfsync_bulk_start(void) 2013223637Sbz{ 2014223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2015223637Sbz 2016226663Sglebius if (V_pf_status.debug >= PF_DEBUG_MISC) 2017226663Sglebius printf("pfsync: received bulk update request\n"); 2018223637Sbz 2019240233Sglebius PFSYNC_BLOCK(sc); 2020223637Sbz 2021240233Sglebius sc->sc_ureq_received = time_uptime; 2022240233Sglebius sc->sc_bulk_hashid = 0; 2023240233Sglebius sc->sc_bulk_stateid = 0; 2024240233Sglebius pfsync_bulk_status(PFSYNC_BUS_START); 2025240233Sglebius callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update, sc); 2026240233Sglebius PFSYNC_BUNLOCK(sc); 2027223637Sbz} 2028223637Sbz 2029240233Sglebiusstatic void 2030223637Sbzpfsync_bulk_update(void *arg) 2031223637Sbz{ 2032223637Sbz struct pfsync_softc *sc = arg; 2033240233Sglebius struct pf_state *s; 2034240233Sglebius int i, sent = 0; 2035223637Sbz 2036240233Sglebius PFSYNC_BLOCK_ASSERT(sc); 2037223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 2038223637Sbz 2039240233Sglebius /* 2040240233Sglebius * Start with last state from previous invocation. 2041240233Sglebius * It may had gone, in this case start from the 2042240233Sglebius * hash slot. 2043240233Sglebius */ 2044240233Sglebius s = pf_find_state_byid(sc->sc_bulk_stateid, sc->sc_bulk_creatorid); 2045223637Sbz 2046240233Sglebius if (s != NULL) 2047240233Sglebius i = PF_IDHASH(s); 2048240233Sglebius else 2049240233Sglebius i = sc->sc_bulk_hashid; 2050240233Sglebius 2051240233Sglebius for (; i <= V_pf_hashmask; i++) { 2052240233Sglebius struct pf_idhash *ih = &V_pf_idhash[i]; 2053240233Sglebius 2054240233Sglebius if (s != NULL) 2055240233Sglebius PF_HASHROW_ASSERT(ih); 2056240233Sglebius else { 2057240233Sglebius PF_HASHROW_LOCK(ih); 2058240233Sglebius s = LIST_FIRST(&ih->states); 2059226663Sglebius } 2060226663Sglebius 2061240233Sglebius for (; s; s = LIST_NEXT(s, entry)) { 2062240233Sglebius 2063240233Sglebius if (sent > 1 && (sc->sc_ifp->if_mtu - sc->sc_len) < 2064240233Sglebius sizeof(struct pfsync_state)) { 2065240233Sglebius /* We've filled a packet. */ 2066240233Sglebius sc->sc_bulk_hashid = i; 2067240233Sglebius sc->sc_bulk_stateid = s->id; 2068240233Sglebius sc->sc_bulk_creatorid = s->creatorid; 2069240233Sglebius PF_HASHROW_UNLOCK(ih); 2070240233Sglebius callout_reset(&sc->sc_bulk_tmo, 1, 2071240233Sglebius pfsync_bulk_update, sc); 2072240233Sglebius goto full; 2073240233Sglebius } 2074240233Sglebius 2075240233Sglebius if (s->sync_state == PFSYNC_S_NONE && 2076240233Sglebius s->timeout < PFTM_MAX && 2077240233Sglebius s->pfsync_time <= sc->sc_ureq_received) { 2078240233Sglebius pfsync_update_state_req(s); 2079240233Sglebius sent++; 2080240233Sglebius } 2081223637Sbz } 2082240233Sglebius PF_HASHROW_UNLOCK(ih); 2083226663Sglebius } 2084130613Smlaier 2085240233Sglebius /* We're done. */ 2086240233Sglebius pfsync_bulk_status(PFSYNC_BUS_END); 2087240233Sglebius 2088240233Sglebiusfull: 2089223637Sbz CURVNET_RESTORE(); 2090223637Sbz} 2091223637Sbz 2092240233Sglebiusstatic void 2093223637Sbzpfsync_bulk_status(u_int8_t status) 2094223637Sbz{ 2095223637Sbz struct { 2096223637Sbz struct pfsync_subheader subh; 2097223637Sbz struct pfsync_bus bus; 2098223637Sbz } __packed r; 2099223637Sbz 2100223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2101130613Smlaier 2102223637Sbz bzero(&r, sizeof(r)); 2103171168Smlaier 2104223637Sbz r.subh.action = PFSYNC_ACT_BUS; 2105223637Sbz r.subh.count = htons(1); 2106240233Sglebius V_pfsyncstats.pfsyncs_oacts[PFSYNC_ACT_BUS]++; 2107223637Sbz 2108223637Sbz r.bus.creatorid = V_pf_status.hostid; 2109223637Sbz r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received); 2110223637Sbz r.bus.status = status; 2111130613Smlaier 2112240233Sglebius PFSYNC_LOCK(sc); 2113223637Sbz pfsync_send_plus(&r, sizeof(r)); 2114240233Sglebius PFSYNC_UNLOCK(sc); 2115126258Smlaier} 2116126261Smlaier 2117240233Sglebiusstatic void 2118223637Sbzpfsync_bulk_fail(void *arg) 2119171168Smlaier{ 2120223637Sbz struct pfsync_softc *sc = arg; 2121171168Smlaier 2122223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 2123171168Smlaier 2124240233Sglebius PFSYNC_BLOCK_ASSERT(sc); 2125240233Sglebius 2126223637Sbz if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { 2127223637Sbz /* Try again */ 2128223637Sbz callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, 2129223637Sbz pfsync_bulk_fail, V_pfsyncif); 2130240233Sglebius PFSYNC_LOCK(sc); 2131223637Sbz pfsync_request_update(0, 0); 2132240233Sglebius PFSYNC_UNLOCK(sc); 2133223637Sbz } else { 2134240233Sglebius /* Pretend like the transfer was ok. */ 2135223637Sbz sc->sc_ureq_sent = 0; 2136223637Sbz sc->sc_bulk_tries = 0; 2137240233Sglebius PFSYNC_LOCK(sc); 2138240233Sglebius if (!(sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) 2139228736Sglebius (*carp_demote_adj_p)(-V_pfsync_carp_adj, 2140228736Sglebius "pfsync bulk fail"); 2141240233Sglebius sc->sc_flags |= PFSYNCF_OK; 2142240233Sglebius PFSYNC_UNLOCK(sc); 2143223637Sbz if (V_pf_status.debug >= PF_DEBUG_MISC) 2144223637Sbz printf("pfsync: failed to receive bulk update\n"); 2145223637Sbz } 2146171168Smlaier 2147223637Sbz CURVNET_RESTORE(); 2148223637Sbz} 2149171168Smlaier 2150240233Sglebiusstatic void 2151223637Sbzpfsync_send_plus(void *plus, size_t pluslen) 2152223637Sbz{ 2153223637Sbz struct pfsync_softc *sc = V_pfsyncif; 2154223637Sbz 2155240233Sglebius PFSYNC_LOCK_ASSERT(sc); 2156226544Sbz 2157240233Sglebius if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) 2158240233Sglebius pfsync_sendout(1); 2159223637Sbz 2160223637Sbz sc->sc_plus = plus; 2161223637Sbz sc->sc_len += (sc->sc_pluslen = pluslen); 2162223637Sbz 2163240233Sglebius pfsync_sendout(1); 2164171168Smlaier} 2165171168Smlaier 2166240233Sglebiusstatic void 2167223637Sbzpfsync_timeout(void *arg) 2168223637Sbz{ 2169223637Sbz struct pfsync_softc *sc = arg; 2170223637Sbz 2171223637Sbz CURVNET_SET(sc->sc_ifp->if_vnet); 2172240233Sglebius PFSYNC_LOCK(sc); 2173240233Sglebius pfsync_push(sc); 2174240233Sglebius PFSYNC_UNLOCK(sc); 2175240233Sglebius CURVNET_RESTORE(); 2176240233Sglebius} 2177223637Sbz 2178240233Sglebiusstatic void 2179240233Sglebiuspfsync_push(struct pfsync_softc *sc) 2180240233Sglebius{ 2181223637Sbz 2182240233Sglebius PFSYNC_LOCK_ASSERT(sc); 2183171168Smlaier 2184240233Sglebius sc->sc_flags |= PFSYNCF_PUSH; 2185240233Sglebius swi_sched(V_pfsync_swi_cookie, 0); 2186223637Sbz} 2187171168Smlaier 2188240233Sglebiusstatic void 2189223637Sbzpfsyncintr(void *arg) 2190226660Sglebius{ 2191226660Sglebius struct pfsync_softc *sc = arg; 2192226831Sglebius struct mbuf *m, *n; 2193226660Sglebius 2194226660Sglebius CURVNET_SET(sc->sc_ifp->if_vnet); 2195226660Sglebius 2196240233Sglebius PFSYNC_LOCK(sc); 2197240233Sglebius if ((sc->sc_flags & PFSYNCF_PUSH) && sc->sc_len > PFSYNC_MINPKT) { 2198240233Sglebius pfsync_sendout(0); 2199240233Sglebius sc->sc_flags &= ~PFSYNCF_PUSH; 2200240233Sglebius } 2201229976Sglebius _IF_DEQUEUE_ALL(&sc->sc_ifp->if_snd, m); 2202240233Sglebius PFSYNC_UNLOCK(sc); 2203226660Sglebius 2204226831Sglebius for (; m != NULL; m = n) { 2205226831Sglebius 2206226831Sglebius n = m->m_nextpkt; 2207226831Sglebius m->m_nextpkt = NULL; 2208240233Sglebius 2209240233Sglebius /* 2210240233Sglebius * We distinguish between a deferral packet and our 2211240233Sglebius * own pfsync packet based on M_SKIP_FIREWALL 2212240233Sglebius * flag. This is XXX. 2213240233Sglebius */ 2214240233Sglebius if (m->m_flags & M_SKIP_FIREWALL) 2215240233Sglebius ip_output(m, NULL, NULL, 0, NULL, NULL); 2216240233Sglebius else if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, 2217240233Sglebius NULL) == 0) 2218226660Sglebius V_pfsyncstats.pfsyncs_opackets++; 2219226660Sglebius else 2220226660Sglebius V_pfsyncstats.pfsyncs_oerrors++; 2221226660Sglebius } 2222226660Sglebius CURVNET_RESTORE(); 2223226660Sglebius} 2224171168Smlaier 2225229850Sglebiusstatic int 2226240233Sglebiuspfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp, void *mship) 2227167710Sbms{ 2228229850Sglebius struct ip_moptions *imo = &sc->sc_imo; 2229229850Sglebius int error; 2230167710Sbms 2231240233Sglebius if (!(ifp->if_flags & IFF_MULTICAST)) 2232229850Sglebius return (EADDRNOTAVAIL); 2233167710Sbms 2234240233Sglebius imo->imo_membership = (struct in_multi **)mship; 2235229850Sglebius imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; 2236229850Sglebius imo->imo_multicast_vif = -1; 2237223637Sbz 2238240233Sglebius if ((error = in_joingroup(ifp, &sc->sc_sync_peer, NULL, 2239229850Sglebius &imo->imo_membership[0])) != 0) { 2240240233Sglebius imo->imo_membership = NULL; 2241229850Sglebius return (error); 2242167710Sbms } 2243229850Sglebius imo->imo_num_memberships++; 2244240233Sglebius imo->imo_multicast_ifp = ifp; 2245229850Sglebius imo->imo_multicast_ttl = PFSYNC_DFLTTL; 2246229850Sglebius imo->imo_multicast_loop = 0; 2247167710Sbms 2248229850Sglebius return (0); 2249167710Sbms} 2250167710Sbms 2251229850Sglebiusstatic void 2252229850Sglebiuspfsync_multicast_cleanup(struct pfsync_softc *sc) 2253229850Sglebius{ 2254229850Sglebius struct ip_moptions *imo = &sc->sc_imo; 2255229850Sglebius 2256229850Sglebius in_leavegroup(imo->imo_membership[0], NULL); 2257229850Sglebius free(imo->imo_membership, M_PFSYNC); 2258229850Sglebius imo->imo_membership = NULL; 2259229850Sglebius imo->imo_multicast_ifp = NULL; 2260229850Sglebius} 2261229850Sglebius 2262229850Sglebius#ifdef INET 2263229850Sglebiusextern struct domain inetdomain; 2264229850Sglebiusstatic struct protosw in_pfsync_protosw = { 2265229964Sglebius .pr_type = SOCK_RAW, 2266229964Sglebius .pr_domain = &inetdomain, 2267229964Sglebius .pr_protocol = IPPROTO_PFSYNC, 2268229964Sglebius .pr_flags = PR_ATOMIC|PR_ADDR, 2269229964Sglebius .pr_input = pfsync_input, 2270229964Sglebius .pr_output = (pr_output_t *)rip_output, 2271229964Sglebius .pr_ctloutput = rip_ctloutput, 2272229964Sglebius .pr_usrreqs = &rip_usrreqs 2273229850Sglebius}; 2274229850Sglebius#endif 2275229850Sglebius 2276241057Sglebiusstatic void 2277241057Sglebiuspfsync_pointers_init() 2278241057Sglebius{ 2279241057Sglebius 2280241057Sglebius PF_RULES_WLOCK(); 2281241057Sglebius pfsync_state_import_ptr = pfsync_state_import; 2282241057Sglebius pfsync_insert_state_ptr = pfsync_insert_state; 2283241057Sglebius pfsync_update_state_ptr = pfsync_update_state; 2284241057Sglebius pfsync_delete_state_ptr = pfsync_delete_state; 2285241057Sglebius pfsync_clear_states_ptr = pfsync_clear_states; 2286241057Sglebius pfsync_defer_ptr = pfsync_defer; 2287241057Sglebius PF_RULES_WUNLOCK(); 2288241057Sglebius} 2289241057Sglebius 2290241057Sglebiusstatic void 2291241057Sglebiuspfsync_pointers_uninit() 2292241057Sglebius{ 2293241057Sglebius 2294241057Sglebius PF_RULES_WLOCK(); 2295241057Sglebius pfsync_state_import_ptr = NULL; 2296241057Sglebius pfsync_insert_state_ptr = NULL; 2297241057Sglebius pfsync_update_state_ptr = NULL; 2298241057Sglebius pfsync_delete_state_ptr = NULL; 2299241057Sglebius pfsync_clear_states_ptr = NULL; 2300241057Sglebius pfsync_defer_ptr = NULL; 2301241057Sglebius PF_RULES_WUNLOCK(); 2302241057Sglebius} 2303241057Sglebius 2304223637Sbzstatic int 2305229850Sglebiuspfsync_init() 2306147261Smlaier{ 2307229850Sglebius VNET_ITERATOR_DECL(vnet_iter); 2308223637Sbz int error = 0; 2309126261Smlaier 2310229850Sglebius VNET_LIST_RLOCK(); 2311229850Sglebius VNET_FOREACH(vnet_iter) { 2312229850Sglebius CURVNET_SET(vnet_iter); 2313241610Sglebius V_pfsync_cloner = if_clone_simple(pfsyncname, 2314241610Sglebius pfsync_clone_create, pfsync_clone_destroy, 1); 2315241610Sglebius error = swi_add(NULL, pfsyncname, pfsyncintr, V_pfsyncif, 2316229850Sglebius SWI_NET, INTR_MPSAFE, &V_pfsync_swi_cookie); 2317229850Sglebius CURVNET_RESTORE(); 2318229850Sglebius if (error) 2319229850Sglebius goto fail_locked; 2320229850Sglebius } 2321229850Sglebius VNET_LIST_RUNLOCK(); 2322229850Sglebius#ifdef INET 2323229850Sglebius error = pf_proto_register(PF_INET, &in_pfsync_protosw); 2324223637Sbz if (error) 2325229850Sglebius goto fail; 2326229850Sglebius error = ipproto_register(IPPROTO_PFSYNC); 2327229850Sglebius if (error) { 2328229850Sglebius pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 2329229850Sglebius goto fail; 2330229850Sglebius } 2331229850Sglebius#endif 2332241057Sglebius pfsync_pointers_init(); 2333223637Sbz 2334223637Sbz return (0); 2335229850Sglebius 2336229850Sglebiusfail: 2337229850Sglebius VNET_LIST_RLOCK(); 2338229850Sglebiusfail_locked: 2339229850Sglebius VNET_FOREACH(vnet_iter) { 2340229850Sglebius CURVNET_SET(vnet_iter); 2341229850Sglebius if (V_pfsync_swi_cookie) { 2342229850Sglebius swi_remove(V_pfsync_swi_cookie); 2343241610Sglebius if_clone_detach(V_pfsync_cloner); 2344229850Sglebius } 2345229850Sglebius CURVNET_RESTORE(); 2346229850Sglebius } 2347229850Sglebius VNET_LIST_RUNLOCK(); 2348229850Sglebius 2349229850Sglebius return (error); 2350147261Smlaier} 2351147261Smlaier 2352229850Sglebiusstatic void 2353229850Sglebiuspfsync_uninit() 2354223637Sbz{ 2355229850Sglebius VNET_ITERATOR_DECL(vnet_iter); 2356223637Sbz 2357241057Sglebius pfsync_pointers_uninit(); 2358223637Sbz 2359229850Sglebius ipproto_unregister(IPPROTO_PFSYNC); 2360229850Sglebius pf_proto_unregister(PF_INET, IPPROTO_PFSYNC, SOCK_RAW); 2361229850Sglebius VNET_LIST_RLOCK(); 2362229850Sglebius VNET_FOREACH(vnet_iter) { 2363229850Sglebius CURVNET_SET(vnet_iter); 2364241610Sglebius if_clone_detach(V_pfsync_cloner); 2365229850Sglebius swi_remove(V_pfsync_swi_cookie); 2366229850Sglebius CURVNET_RESTORE(); 2367229850Sglebius } 2368229850Sglebius VNET_LIST_RUNLOCK(); 2369223637Sbz} 2370223637Sbz 2371223637Sbzstatic int 2372126261Smlaierpfsync_modevent(module_t mod, int type, void *data) 2373126261Smlaier{ 2374126261Smlaier int error = 0; 2375126261Smlaier 2376126261Smlaier switch (type) { 2377126261Smlaier case MOD_LOAD: 2378229850Sglebius error = pfsync_init(); 2379126261Smlaier break; 2380229850Sglebius case MOD_QUIESCE: 2381229850Sglebius /* 2382229850Sglebius * Module should not be unloaded due to race conditions. 2383229850Sglebius */ 2384240836Sglebius error = EBUSY; 2385229850Sglebius break; 2386126261Smlaier case MOD_UNLOAD: 2387229850Sglebius pfsync_uninit(); 2388126261Smlaier break; 2389126261Smlaier default: 2390126261Smlaier error = EINVAL; 2391126261Smlaier break; 2392126261Smlaier } 2393126261Smlaier 2394229850Sglebius return (error); 2395126261Smlaier} 2396126261Smlaier 2397126261Smlaierstatic moduledata_t pfsync_mod = { 2398241610Sglebius pfsyncname, 2399126261Smlaier pfsync_modevent, 2400241394Skevlo 0 2401126261Smlaier}; 2402126261Smlaier 2403126261Smlaier#define PFSYNC_MODVER 1 2404126261Smlaier 2405229853SglebiusDECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 2406126261SmlaierMODULE_VERSION(pfsync, PFSYNC_MODVER); 2407223637SbzMODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); 2408